|
|
1.1 root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
2:
3: /* user interface for X tcl/tk */
4:
5: #include <string.h>
6: #include <unistd.h>
7: #include <stdlib.h>
8: #include <errno.h>
9: #include <stdarg.h>
10:
1.1.1.2 root 11: #include <sys/types.h> /* these three are for saving with -save */
1.1 root 12: #include <sys/stat.h>
13: #include <fcntl.h>
14:
15: #include "generator.h"
16:
17: #ifdef HAVE_TCL8_0_H
18: # include <tcl8.0.h>
19: #else
20: # include <tcl.h>
21: #endif
22:
23: #ifdef HAVE_TK8_0_H
24: # include <tk8.0.h>
25: #else
26: # include <tk.h>
27: #endif
28:
29: #include <X11/Xlib.h>
30: #include <X11/Xutil.h>
31:
32: #include "diss68k.h"
33: #include "cpu68k.h"
34: #include "cpuz80.h"
35: #include "ui.h"
36: #include "vdp.h"
37: #include "mem68k.h"
38: #include "event.h"
1.1.1.3 ! root 39: #include "state.h"
1.1 root 40:
41: #ifdef XF86DGA
42: #include <X11/extensions/xf86dga.h>
43: #endif
44:
45: /*
46: #ifndef XInitImage
47: #define XInitImage _XInitImageFuncPtrs
48: Status _XInitImageFuncPtrs(XImage *);
49: #endif
50: */
51:
52: #define MAXDEPTHBYTES 4
53:
54: /*** forward reference declarations ***/
55:
1.1.1.2 root 56: int ui_loadimage(Tcl_Interp * interp, const char *filename);
57: int ui_loadsavepos(Tcl_Interp * interp, const char *filename);
58: int ui_redrawdump(Tcl_Interp * interp, char *textwidget);
1.1 root 59: void ui_updateregs(void);
60: void ui_updatestr(char *var, char *val);
61: void ui_updateint(char *var, int val);
62: int ui_getint(int *cint, char *tclint);
63: int ui_setstr(const char *name, const char *value);
1.1.1.2 root 64: void ui_keypress(ClientData cd, XEvent * event);
65: void ui_enterleave(ClientData cd, XEvent * event);
1.1 root 66: int ui_topbit(unsigned long int bits);
67: void ui_endframe(void);
68: void ui_convertdata(uint8 *indata, uint8 *outdata, unsigned int pixels,
1.1.1.2 root 69: unsigned int lineoffset, unsigned int scale,
70: unsigned int depth, unsigned int basepixel);
71: void ui_convertdata_smooth(uint8 *indata, uint8 *outdata,
72: unsigned int pixels, unsigned int lineoffset,
73: unsigned int depth);
1.1.1.3 ! root 74: static char *ui_setinfo(t_cartinfo * cartinfo);
1.1 root 75:
76: #ifdef XF86DGA
77: void ui_fullscreen(int onoff);
78: #endif
79:
80: /*** static variables ***/
81:
82: static Tk_Window mainwin;
83: static Bool xsync = False;
84: static Bool save = False;
85: static Tcl_Interp *interp;
86: static char *imagedata;
87: static XImage *image;
88: static GC gc = NULL;
89: static unsigned int scale = 1;
90: static unsigned int smooth = 0;
91: static Visual *visual;
92: static Colormap cmap;
93: static unsigned long visual_bluemask;
94: static unsigned long visual_redmask;
95: static unsigned long visual_greenmask;
96: static int visual_bluepos;
97: static int visual_redpos;
98: static int visual_greenpos;
99: static unsigned int basepixel;
100: static unsigned int depth;
101: static unsigned int frameskip = 1;
102: static Display *ui_display = NULL;
103: static Screen *ui_screen = NULL;
104: static int ui_screenno = 0;
1.1.1.2 root 105: static int ui_dga = 0; /* enable/disable availability flag */
106: static int ui_dga_state = 0; /* DGA on/off */
1.1 root 107: static uint32 ui_palcache[192];
1.1.1.2 root 108: static int ui_vdpsimple = 1; /* simple vdp enable/disable */
109: static char *ui_initload = NULL; /* filename to load on init */
110: static unsigned int state = 0; /* 0=stop,1=pause,2=play */
1.1 root 111:
112: #ifdef XF86DGA
113: static int dga_major, dga_minor;
114: static int dga_eventb, dga_errorb;
115: static int dga_flags;
116: static char *dga_baseaddr;
117: static int dga_width, dga_banksize, dga_memsize;
118: static int dga_xsize, dga_ysize;
119: static char *dga_start;
120: #endif
121:
122: /*** Define our own arguments for Tk to process ***/
123:
124: static Tk_ArgvInfo argtable[] = {
125: /* { "-display", TK_ARGV_STRING, (char*) NULL, (char*) &display,
1.1.1.2 root 126: "Display to use" }, */
127: {"-sync", TK_ARGV_CONSTANT, (char *)True, (char *)&xsync,
128: "Turn on synchronous X"},
129: {"-save", TK_ARGV_CONSTANT, (char *)True, (char *)&save,
130: "Save ROM as bin"},
131: {"", TK_ARGV_END, (char *)NULL, (char *)NULL, (char *)NULL}
1.1 root 132: };
133:
134: /*** Error handler for X protocol errors ***/
135:
1.1.1.2 root 136: static int errorhandler(ClientData data, XErrorEvent * err)
137: {
1.1.1.3 ! root 138: (void)data;
1.1 root 139: ui_err("X error %d, request %d, minor %d", err->error_code,
1.1.1.2 root 140: err->request_code, err->minor_code);
1.1 root 141: return 0;
142: }
143:
144: /*** Gen_Load type pathname ***/
145:
1.1.1.2 root 146: int
147: Gen_Load(ClientData cdata, Tcl_Interp * interp, int objc,
148: Tcl_Obj * const objv[])
1.1 root 149: {
150: int i;
151:
1.1.1.3 ! root 152: (void)cdata;
1.1 root 153: if (objc != 3) {
1.1.1.2 root 154: Tcl_SetResult(interp,
155: "wrong # args: should be \"Gen_Load type pathName\"",
156: TCL_STATIC);
1.1 root 157: return TCL_ERROR;
158: }
159: if (Tcl_GetIntFromObj(interp, objv[1], &i) != TCL_OK)
160: return TCL_ERROR;
161: switch (i) {
162: case 0:
163: return ui_loadimage(interp, Tcl_GetStringFromObj(objv[2], NULL));
164: case 1:
165: return ui_loadsavepos(interp, Tcl_GetStringFromObj(objv[2], NULL));
166: }
167: Tcl_SetResult(interp, "invalid type: should be image (0) or savepos (1)\n",
1.1.1.2 root 168: TCL_STATIC);
1.1 root 169: return TCL_ERROR;
170: }
171:
172: /*** Gen_Save pathname - saves the current state of play in a savegame ***/
173:
1.1.1.2 root 174: int
175: Gen_Save(ClientData cdata, Tcl_Interp * interp, int objc,
176: Tcl_Obj * const objv[])
1.1 root 177: {
1.1.1.3 ! root 178: (void)cdata;
1.1 root 179: if (objc != 2) {
180: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Save pathName\"",
1.1.1.2 root 181: TCL_STATIC);
1.1 root 182: return TCL_ERROR;
183: }
184: LOG_NORMAL(("Save! %s\n", Tcl_GetStringFromObj(objv[1], NULL)));
185: return TCL_OK;
186: }
187:
188: /*** Gen_Dump widgetname yview <params from scrollbar> ***/
189:
1.1.1.2 root 190: int Gen_Dump(ClientData cdata, Tcl_Interp * interp, int argc, char *argv[])
1.1 root 191: {
192: int si_line, memtype, dumptype, offset, lines;
193: double si_fraction;
194: char tmp[256];
195: Tcl_Obj *varobj, *outobj;
196: Tk_Window window;
197: uint8 *mem_where;
198: unsigned int mem_start, mem_len;
199:
1.1.1.3 ! root 200: (void)cdata;
1.1 root 201: if (!cpu68k_rom) {
202: Tcl_SetResult(interp, "Nothing to display", TCL_STATIC);
203: return TCL_ERROR;
204: }
205:
206: window = Tk_NameToWindow(interp, argv[1], Tk_MainWindow(interp));
207: if (!window) {
208: Tcl_SetResult(interp, "bad widget passed to Gen_Dump", TCL_STATIC);
209: return TCL_ERROR;
210: }
211:
212: /* get memtype variable */
213: sprintf(tmp, "%s.memtype", argv[1]);
214: varobj = Tcl_NewStringObj(tmp, -1);
215: Tcl_IncrRefCount(varobj);
216: if (!(outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY))) {
217: Tcl_SetResult(interp, ".memtype variable not set", TCL_STATIC);
218: return TCL_ERROR;
219: }
220: Tcl_IncrRefCount(outobj);
221: if (Tcl_GetIntFromObj(interp, outobj, &memtype) != TCL_OK) {
222: return TCL_ERROR;
223: }
224: Tcl_DecrRefCount(varobj);
225: Tcl_DecrRefCount(outobj);
226:
227: /* get dumptype variable */
228: sprintf(tmp, "%s.dumptype", argv[1]);
229: varobj = Tcl_NewStringObj(tmp, -1);
230: Tcl_IncrRefCount(varobj);
231: if (!(outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY))) {
232: Tcl_SetResult(interp, ".dumptype variable not set", TCL_STATIC);
233: return TCL_ERROR;
234: }
235: Tcl_IncrRefCount(outobj);
236: if (Tcl_GetIntFromObj(interp, outobj, &dumptype) != TCL_OK) {
237: return TCL_ERROR;
238: }
239: Tcl_DecrRefCount(varobj);
240: Tcl_DecrRefCount(outobj);
241:
242: /* get offset variable */
243: sprintf(tmp, "%s.offset", argv[1]);
244: varobj = Tcl_NewStringObj(tmp, -1);
245: Tcl_IncrRefCount(varobj);
246: if (!(outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY))) {
247: Tcl_SetResult(interp, ".offset variable not set", TCL_STATIC);
248: return TCL_ERROR;
249: }
250: Tcl_IncrRefCount(outobj);
251: if (Tcl_GetIntFromObj(interp, outobj, &offset) != TCL_OK) {
252: return TCL_ERROR;
253: }
254: Tcl_DecrRefCount(varobj);
255: Tcl_DecrRefCount(outobj);
256:
257: /* get lines variable */
258: sprintf(tmp, "%s.lines", argv[1]);
259: varobj = Tcl_NewStringObj(tmp, -1);
260: Tcl_IncrRefCount(varobj);
261: if (!(outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY))) {
262: Tcl_SetResult(interp, ".lines variable not set", TCL_STATIC);
263: return TCL_ERROR;
264: }
265: Tcl_IncrRefCount(outobj);
266: if (Tcl_GetIntFromObj(interp, outobj, &lines) != TCL_OK) {
267: return TCL_ERROR;
268: }
269: Tcl_DecrRefCount(varobj);
270: Tcl_DecrRefCount(outobj);
271:
1.1.1.2 root 272: switch (memtype) {
1.1 root 273: case 1:
274: mem_where = cpu68k_ram;
275: mem_start = 0xFF0000;
276: mem_len = 0x10000;
277: break;
278: case 2:
279: mem_where = vdp_vram;
280: mem_start = 0x0;
281: mem_len = LEN_VRAM;
282: break;
283: case 3:
284: mem_where = vdp_cram;
285: mem_start = 0x0;
286: mem_len = LEN_CRAM;
287: break;
288: case 4:
289: mem_where = vdp_vsram;
290: mem_start = 0x0;
291: mem_len = LEN_VSRAM;
292: break;
293: case 5:
294: mem_where = cpuz80_ram;
295: mem_start = 0x0;
296: mem_len = LEN_SRAM;
297: break;
1.1.1.2 root 298: default: /* 0 */
1.1 root 299: mem_where = cpu68k_rom;
300: mem_start = 0;
301: mem_len = cpu68k_romlen;
302: break;
303: }
304:
305: if (!strcasecmp(argv[2], "yview")) {
1.1.1.2 root 306: switch (Tk_GetScrollInfo
307: (interp, argc - 1, argv + 1, &si_fraction, &si_line)) {
1.1 root 308: case TK_SCROLL_MOVETO:
1.1.1.2 root 309: offset = (int)(si_fraction * mem_len) & (~1);
1.1 root 310: break;
311: case TK_SCROLL_UNITS:
312: if (offset < 256 && (si_line > 0)) {
1.1.1.2 root 313: offset = (si_line * 4) + offset;
314: offset &= ~3;
1.1 root 315: } else if ((offset <= 256) && (si_line < 0)) {
1.1.1.2 root 316: offset = (si_line * 4) + offset;
317: offset &= ~3;
1.1 root 318: } else {
1.1.1.2 root 319: offset = (si_line * 2) + offset;
1.1 root 320: }
321: break;
322: case TK_SCROLL_PAGES:
1.1.1.2 root 323: offset = si_line * lines * 2 + offset;
1.1 root 324: break;
325: default:
326: Tcl_SetResult(interp, "unknown yview command parameter", TCL_STATIC);
327: return TCL_ERROR;
328: }
329: } else if (!strcasecmp(argv[2], "redraw")) {
330: return ui_redrawdump(interp, argv[1]);
331: } else {
332: Tcl_SetResult(interp, "unknown command type (must be yview or redraw)",
1.1.1.2 root 333: TCL_STATIC);
1.1 root 334: return TCL_ERROR;
1.1.1.2 root 335: }
1.1 root 336: if (offset >= (signed int)mem_len)
1.1.1.2 root 337: offset = mem_len - 2;
1.1 root 338: if (offset < 0)
339: offset = 0;
340: sprintf(tmp, "%s.offset", argv[1]);
341: varobj = Tcl_NewStringObj(tmp, -1);
342: Tcl_IncrRefCount(varobj);
343: if (Tcl_ObjSetVar2(interp, varobj, NULL, Tcl_NewIntObj(offset),
1.1.1.2 root 344: TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
1.1 root 345: return TCL_ERROR;
346: }
347: Tcl_DecrRefCount(varobj);
348: ui_redrawdump(interp, argv[1]);
349: return TCL_OK;
350: }
1.1.1.2 root 351:
1.1 root 352: /*** Gen_Step - step through one instruction ***/
353:
1.1.1.2 root 354: int
355: Gen_Step(ClientData cdata, Tcl_Interp * interp, int objc,
356: Tcl_Obj * const objv[])
1.1 root 357: {
1.1.1.3 ! root 358: (void)cdata;
! 359: (void)objv;
1.1 root 360: if (objc != 1) {
1.1.1.2 root 361: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Step\"", TCL_STATIC);
1.1 root 362: return TCL_ERROR;
363: }
364: event_dostep();
365: ui_updateregs();
366: return TCL_OK;
367: }
368:
369: /*** Gen_Cont - start executing ***/
370:
1.1.1.2 root 371: int
372: Gen_Cont(ClientData cdata, Tcl_Interp * interp, int objc,
373: Tcl_Obj * const objv[])
1.1 root 374: {
375: char *stopstr;
376: uint32 stopaddr;
377: Tcl_Obj *obj;
378: int i;
379:
1.1.1.3 ! root 380: (void)cdata;
! 381: (void)objv;
1.1 root 382: if (objc != 1) {
1.1.1.2 root 383: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Cont\"", TCL_STATIC);
1.1 root 384: return TCL_ERROR;
385: }
386: obj = Tcl_ObjGetVar2(interp, Tcl_NewStringObj("regs.stop", -1), NULL,
1.1.1.2 root 387: TCL_GLOBAL_ONLY);
1.1 root 388: stopstr = Tcl_GetStringFromObj(obj, NULL);
389: if (!stopstr) {
390: Tcl_SetResult(interp, "Cannot read regs.stop", TCL_STATIC);
391: return TCL_ERROR;
392: }
393: stopaddr = strtol(stopstr, NULL, 16);
394: gen_quit = 0;
395: LOG_NORMAL(("Continuing from %08X", regs.pc));
396: do {
397: while (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT));
398: for (i = 0; i < 128; i++) {
399: event_dostep();
400: if ((regs.pc & 0xFFFFFF) == stopaddr || gen_quit)
1.1.1.2 root 401: break;
1.1 root 402: }
1.1.1.2 root 403: }
404: while ((regs.pc & 0xFFFFFF) != stopaddr && !gen_quit);
1.1 root 405: LOG_NORMAL(("End of continuation, stopped at %08X", regs.pc));
406: ui_updateregs();
407: if (gen_quit)
408: LOG_NORMAL(("Stopped."));
409: gen_quit = 0;
410: return TCL_OK;
411: }
412:
413: /*** Gen_FrameStep - step through one frame ***/
414:
1.1.1.2 root 415: int
416: Gen_FrameStep(ClientData cdata, Tcl_Interp * interp, int objc,
417: Tcl_Obj * const objv[])
1.1 root 418: {
1.1.1.3 ! root 419: (void)cdata;
! 420: (void)objv;
1.1 root 421: if (objc != 1) {
422: Tcl_SetResult(interp, "wrong # args: should be \"Gen_FrameStep\"",
1.1.1.2 root 423: TCL_STATIC);
1.1 root 424: return TCL_ERROR;
425: }
426: gen_quit = 0;
427: do {
428: event_doframe();
429: while (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT));
1.1.1.2 root 430: }
431: while (!gen_quit);
1.1 root 432: ui_updateregs();
433: if (gen_quit)
434: LOG_NORMAL(("Stopped."));
435: gen_quit = 0;
436:
437: return TCL_OK;
438: }
439:
440: /*** Gen_SpriteList - print sprite information ***/
441:
1.1.1.2 root 442: int
443: Gen_SpriteList(ClientData cdata, Tcl_Interp * interp, int objc,
444: Tcl_Obj * const objv[])
1.1 root 445: {
1.1.1.3 ! root 446: (void)cdata;
! 447: (void)objv;
1.1 root 448: if (objc != 1) {
449: Tcl_SetResult(interp, "wrong # args: should be \"Gen_SpriteList\"",
1.1.1.2 root 450: TCL_STATIC);
1.1 root 451: return TCL_ERROR;
452: }
453: vdp_spritelist();
454: return TCL_OK;
455: }
456:
457: /*** Gen_Change - there has been a change in parameter ***/
458:
1.1.1.2 root 459: int
460: Gen_Change(ClientData cdata, Tcl_Interp * interp, int objc,
461: Tcl_Obj * const objv[])
1.1 root 462: {
463: unsigned int oldscale = scale;
464: unsigned int newstate;
465:
1.1.1.3 ! root 466: (void)cdata;
! 467: (void)objv;
1.1 root 468: if (objc != 1) {
469: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Change\"",
1.1.1.2 root 470: TCL_STATIC);
1.1 root 471: return TCL_ERROR;
472: }
473:
474: ui_getint((int *)&ui_vdpsimple, "vdpsimple");
1.1.1.2 root 475: ui_getint((int *)&vdp_layerB, "layerB");
476: ui_getint((int *)&vdp_layerBp, "layerBp");
477: ui_getint((int *)&vdp_layerA, "layerA");
478: ui_getint((int *)&vdp_layerAp, "layerAp");
479: ui_getint((int *)&vdp_layerW, "layerW");
480: ui_getint((int *)&vdp_layerWp, "layerWp");
481: ui_getint((int *)&vdp_layerH, "layerH");
482: ui_getint((int *)&vdp_layerS, "layerS");
483: ui_getint((int *)&vdp_layerSp, "layerSp");
484: ui_getint((int *)&frameskip, "skip");
485: ui_getint((int *)&newstate, "state");
1.1 root 486: ui_getint((int *)&gen_loglevel, "loglevel");
487:
488: ui_getint(&scale, "scale");
489: ui_getint(&smooth, "smooth");
490:
491: if (scale != oldscale) {
492: XDestroyImage(image);
1.1.1.2 root 493: if ((imagedata = malloc(320 * 240 * scale * scale * (depth / 8))) == NULL)
1.1 root 494: ui_err("%s: Out of memory!");
1.1.1.2 root 495: memset(imagedata, 0, 320 * 240 * scale * scale * (depth / 8));
496: if ((image =
497: XCreateImage(ui_display, visual, depth, ZPixmap, 0, imagedata,
498: 320 * scale, 240 * scale, 8, 0)) == NULL) {
1.1 root 499: Tcl_SetResult(interp, "unable to create image", TCL_STATIC);
500: return TCL_ERROR;
501: }
502: image->bits_per_pixel = depth;
503: XInitImage(image);
504: }
505: #ifdef XF86DGA
1.1.1.2 root 506: dga_start = dga_baseaddr + ((depth / 8) *
507: (dga_xsize * ((dga_ysize - (240 * scale)) / 2) +
508: ((dga_xsize - (320 * scale)) / 2)));
1.1 root 509: #endif
510:
511: if (newstate != state) {
1.1.1.2 root 512: switch (newstate) {
1.1 root 513: case 0:
514: /* stop */
515: break;
516: case 1:
517: /* pause */
518: break;
519: case 2:
520: /* play */
521: if (cpu68k_rom == NULL) {
1.1.1.2 root 522: Tcl_SetResult(interp, "No ROM loaded\n", TCL_STATIC);
523: return TCL_ERROR;
1.1 root 524: }
525: if (state == 0)
1.1.1.2 root 526: gen_reset();
1.1 root 527: break;
528: }
529: state = newstate;
530: }
531: return TCL_OK;
532: }
533:
534: /*** Gen_Initialised ***/
535:
1.1.1.2 root 536: int
537: Gen_Initialised(ClientData cdata, Tcl_Interp * interp, int objc,
538: Tcl_Obj * const objv[])
1.1 root 539: {
540: char *p;
541: int f;
542: char buffer[256];
543:
1.1.1.3 ! root 544: (void)cdata;
! 545: (void)objv;
1.1 root 546: if (objc != 1) {
547: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Change\"",
1.1.1.2 root 548: TCL_STATIC);
1.1 root 549: return TCL_ERROR;
550: }
551: if (ui_initload) {
552: p = gen_loadimage(ui_initload);
553: if (p) {
554: Tcl_SetResult(interp, p, TCL_STATIC);
555: return TCL_ERROR;
556: }
557: ui_updateregs();
558: if (save) {
1.1.1.2 root 559: snprintf(buffer, sizeof(buffer) - 1, "./%s (%X-%s)",
560: gen_cartinfo.name_overseas, gen_cartinfo.checksum,
561: gen_cartinfo.country);
1.1 root 562: f = 0;
1.1.1.2 root 563: if ((f = open(buffer, O_CREAT | O_EXCL | O_WRONLY, 0777)) == -1 ||
564: write(f, cpu68k_rom, cpu68k_romlen) == -1 || close(f) == -1) {
565: Tcl_SetResult(interp, strerror(errno), TCL_STATIC);
566: return TCL_ERROR;
1.1 root 567: }
568: LOG_REQUEST(("Saved '%s'", buffer));
569: }
570: }
571: return TCL_OK;
572: }
573:
574: /*** Gen_Reset ***/
575:
1.1.1.2 root 576: int
577: Gen_Reset(ClientData cdata, Tcl_Interp * interp, int objc,
578: Tcl_Obj * const objv[])
1.1 root 579: {
580: int resetitem;
581:
1.1.1.3 ! root 582: (void)cdata;
1.1 root 583: if (objc != 2) {
584: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Reset <x>\"",
1.1.1.2 root 585: TCL_STATIC);
1.1 root 586: return TCL_ERROR;
587: }
588: Tcl_GetIntFromObj(interp, objv[1], &resetitem);
1.1.1.2 root 589: switch (resetitem) {
590: case 1: /* z80 */
1.1 root 591: cpuz80_reset();
592: break;
593: default:
594: Tcl_SetResult(interp, "unknown reset item", TCL_STATIC);
595: return TCL_ERROR;
596: }
597: return TCL_OK;
598: }
599:
600: /*** ui_getint - get a TCL integer into a C int ***/
601:
602: int ui_getint(int *cint, char *tclint)
603: {
604: Tcl_Obj *valobj, *varobj;
605:
606: varobj = Tcl_NewStringObj(tclint, -1);
607: Tcl_IncrRefCount(varobj);
608: if (!(valobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY))) {
609: Tcl_SetResult(interp, "variable not set", TCL_STATIC);
610: return TCL_ERROR;
611: }
612: Tcl_IncrRefCount(valobj);
613: if (Tcl_GetIntFromObj(interp, valobj, cint) != TCL_OK) {
614: return TCL_ERROR;
615: }
616: Tcl_DecrRefCount(varobj);
617: Tcl_DecrRefCount(valobj);
618: return TCL_OK;
619: }
620:
621: /*** ui_setstr - store a string into a TCL variable ***/
622:
623: int ui_setstr(const char *name, const char *value)
624: {
625: Tcl_Obj *strobj, *varobj, *outobj;
626:
627: varobj = Tcl_NewStringObj((char *)name, -1);
628: Tcl_IncrRefCount(varobj);
629: strobj = Tcl_NewStringObj((char *)value, -1);
630: Tcl_IncrRefCount(strobj);
631: if (!(outobj = Tcl_ObjSetVar2(interp, varobj, NULL, strobj,
1.1.1.2 root 632: TCL_GLOBAL_ONLY))) {
1.1 root 633: return -1;
634: }
635: Tcl_DecrRefCount(varobj);
636: Tcl_DecrRefCount(strobj);
637: return 0;
638: }
639:
640: /*** Gen_Regs - display registers ***/
641:
1.1.1.2 root 642: int
643: Gen_Regs(ClientData cdata, Tcl_Interp * interp, int objc,
644: Tcl_Obj * const objv[])
1.1 root 645: {
1.1.1.3 ! root 646: (void)cdata;
! 647: (void)objv;
1.1 root 648: if (objc != 1) {
1.1.1.2 root 649: Tcl_SetResult(interp, "wrong # args: should be \"Gen_Regs\"", TCL_STATIC);
1.1 root 650: return TCL_ERROR;
651: }
652: vdp_showregs();
653: return TCL_OK;
654: }
655:
656: /*** Gen_VDPDescribe - describe vdp state ***/
657:
1.1.1.2 root 658: int
659: Gen_VDPDescribe(ClientData cdata, Tcl_Interp * interp, int objc,
660: Tcl_Obj * const objv[])
1.1 root 661: {
1.1.1.3 ! root 662: (void)cdata;
! 663: (void)objv;
1.1 root 664: if (objc != 1) {
665: Tcl_SetResult(interp, "wrong # args: should be \"Gen_VDPDescribe\"",
1.1.1.2 root 666: TCL_STATIC);
1.1 root 667: return TCL_ERROR;
668: }
669: vdp_describe();
670: return TCL_OK;
671: }
672:
1.1.1.2 root 673: int ui_redrawdump(Tcl_Interp * interp, char *textwidget)
1.1 root 674: {
1.1.1.3 ! root 675: int offset, line, listlen, words, memtype;
1.1 root 676: char tmp[256], dumpline[128];
677: Tcl_Obj *varobj, *outobj, *paramobj;
678: uint8 *mem_where;
679: unsigned int mem_start, mem_len;
680:
681: /* get offset variable */
682: sprintf(tmp, "%s.offset", textwidget);
683: varobj = Tcl_NewStringObj(tmp, -1);
684: Tcl_IncrRefCount(varobj);
685: if ((outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY |
1.1.1.2 root 686: TCL_LEAVE_ERR_MSG)) == NULL) {
1.1 root 687: return TCL_ERROR;
688: }
689: Tcl_IncrRefCount(outobj);
690: if (Tcl_GetIntFromObj(interp, outobj, &offset) != TCL_OK) {
691: return TCL_ERROR;
692: }
693: Tcl_DecrRefCount(outobj);
694: Tcl_DecrRefCount(varobj);
695:
696: /* get memtype variable */
697: sprintf(tmp, "%s.memtype", textwidget);
698: varobj = Tcl_NewStringObj(tmp, -1);
699: Tcl_IncrRefCount(varobj);
700: if ((outobj = Tcl_ObjGetVar2(interp, varobj, NULL, TCL_GLOBAL_ONLY |
1.1.1.2 root 701: TCL_LEAVE_ERR_MSG)) == NULL) {
1.1 root 702: return TCL_ERROR;
703: }
704: Tcl_IncrRefCount(outobj);
705: if (Tcl_GetIntFromObj(interp, outobj, &memtype) != TCL_OK) {
706: return TCL_ERROR;
707: }
708: Tcl_DecrRefCount(varobj);
709: Tcl_DecrRefCount(outobj);
710:
711: /* clear current text display */
712: sprintf(tmp, "%s.main delete 1.0 end", textwidget);
713: varobj = Tcl_NewStringObj(tmp, -1);
714: Tcl_IncrRefCount(varobj);
715: if (Tcl_EvalObj(interp, varobj) == TCL_ERROR) {
716: return TCL_ERROR;
717: }
718: Tcl_DecrRefCount(varobj);
719:
1.1.1.2 root 720: switch (memtype) {
1.1 root 721: case 1:
722: mem_where = cpu68k_ram;
723: mem_start = 0xFF0000;
724: mem_len = 0x10000;
725: break;
726: case 2:
727: mem_where = vdp_vram;
728: mem_start = 0x0;
729: mem_len = LEN_VRAM;
730: break;
731: case 3:
732: mem_where = vdp_cram;
733: mem_start = 0x0;
734: mem_len = LEN_CRAM;
735: break;
736: case 4:
737: mem_where = vdp_vsram;
738: mem_start = 0x0;
739: mem_len = LEN_VSRAM;
740: break;
741: case 5:
742: mem_where = cpuz80_ram;
743: mem_start = 0x0;
744: mem_len = LEN_SRAM;
745: break;
1.1.1.2 root 746: default: /* 0 */
1.1 root 747: mem_where = cpu68k_rom;
748: mem_start = 0;
749: mem_len = cpu68k_romlen;
750: break;
751: }
752:
753: line = 1;
1.1.1.2 root 754: while (line <= 100) { /* do dump loop */
1.1 root 755:
756: /* first check visibility of line by checking bbox of char 0 on the line */
757: sprintf(tmp, "[%s.main bbox %d.0]", textwidget, line);
758: varobj = Tcl_NewStringObj(tmp, -1);
759: Tcl_IncrRefCount(varobj);
760: if (Tcl_ExprObj(interp, varobj, &outobj) == TCL_ERROR) {
761: return TCL_ERROR;
762: }
763: if (Tcl_ListObjLength(interp, outobj, &listlen) == TCL_ERROR) {
764: return TCL_ERROR;
765: }
766: Tcl_DecrRefCount(outobj);
767: Tcl_DecrRefCount(varobj);
768:
769: if (listlen == 0 || (unsigned int)offset > mem_len) {
770: break;
771: }
772:
773: /* this line is visible so disassemble it */
774: if ((unsigned int)offset == mem_len) {
1.1.1.3 ! root 775: sprintf(dumpline, "---end\n");
1.1 root 776: words = 1;
777: } else {
1.1.1.2 root 778: words = diss68k_getdumpline(mem_start + offset, mem_where + offset,
779: dumpline);
1.1 root 780: }
781:
782: /* insert line at end of disassembly */
783: sprintf(tmp, "%s.main insert end {%s}", textwidget, dumpline);
784: varobj = Tcl_NewStringObj(tmp, -1);
785: Tcl_IncrRefCount(varobj);
786: if (Tcl_EvalObj(interp, varobj) == TCL_ERROR) {
787: return TCL_ERROR;
788: }
789: Tcl_DecrRefCount(varobj);
790:
791: /* increment address and line number and loop */
1.1.1.2 root 792: offset += words * 2;
1.1 root 793: line++;
794: }
795: line--;
796:
797: /* update scrollbar */
1.1.1.2 root 798: sprintf(tmp, "%s.bar set %f %f", textwidget, offset / (double)mem_len,
799: (offset + line * 2) / (double)mem_len);
1.1 root 800: varobj = Tcl_NewStringObj(tmp, -1);
801: Tcl_IncrRefCount(varobj);
802: if (Tcl_EvalObj(interp, varobj) == TCL_ERROR) {
803: return TCL_ERROR;
804: }
805: Tcl_DecrRefCount(varobj);
806:
807: /* record number of lines for paging function */
808: sprintf(tmp, "%s.lines", textwidget);
809: varobj = Tcl_NewStringObj(tmp, -1);
810: paramobj = Tcl_NewIntObj(line);
811: Tcl_IncrRefCount(varobj);
812: Tcl_IncrRefCount(paramobj);
813: if (Tcl_ObjSetVar2(interp, varobj, NULL, paramobj,
1.1.1.2 root 814: TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
1.1 root 815: return TCL_ERROR;
816: }
817: Tcl_DecrRefCount(varobj);
818: Tcl_DecrRefCount(paramobj);
819: return TCL_OK;
820: }
821:
822: /*** Program entry point ***/
823:
824: int ui_init(int argc, char *argv[])
825: {
826: int i;
827: unsigned long plane_masks[1];
828: unsigned long colours[256];
829: XColor xcolor;
830:
831: /* Create tcl interpreter and parse arguments */
832: interp = Tcl_CreateInterp();
833: if (Tk_ParseArgv(interp, NULL, &argc, argv, argtable, 0) != TCL_OK)
834: ui_err("%s: %s", argv[0], Tcl_GetStringResult(interp));
835: if (argc < 1 || argc > 2)
836: ui_err("Usage: %s [<file>]", argv[0]);
837:
838: /* Initialise tcl and tk */
839: if (Tcl_Init(interp) != TCL_OK)
840: ui_err("%s: Tcl_Init failed: %s", argv[0], Tcl_GetStringResult(interp));
841: if (Tk_Init(interp) != TCL_OK)
842: ui_err("%s: Tk_Init failed: %s", argv[0], Tcl_GetStringResult(interp));
843: if ((mainwin = Tk_MainWindow(interp)) == NULL)
844: ui_err("%s: No main window!", argv[0]);
845:
846: ui_display = Tk_Display(mainwin);
847: ui_screen = Tk_Screen(mainwin);
848: ui_screenno = Tk_ScreenNumber(mainwin);
849:
850: /* Configure error handling */
1.1.1.2 root 851: Tk_CreateErrorHandler(ui_display, -1, -1, -1, errorhandler, (char *)NULL);
1.1 root 852: if (xsync)
853: XSynchronize(ui_display, True);
854:
855: /* Create new Tcl commands */
856: Tcl_CreateObjCommand(interp, "Gen_Load", Gen_Load, NULL, NULL);
857: Tcl_CreateObjCommand(interp, "Gen_Save", Gen_Save, NULL, NULL);
858: Tcl_CreateCommand(interp, "Gen_Dump", Gen_Dump, NULL, NULL);
859: Tcl_CreateObjCommand(interp, "Gen_Step", Gen_Step, NULL, NULL);
860: Tcl_CreateObjCommand(interp, "Gen_FrameStep", Gen_FrameStep, NULL, NULL);
861: Tcl_CreateObjCommand(interp, "Gen_Cont", Gen_Cont, NULL, NULL);
862: Tcl_CreateObjCommand(interp, "Gen_Change", Gen_Change, NULL, NULL);
863: Tcl_CreateObjCommand(interp, "Gen_Regs", Gen_Regs, NULL, NULL);
1.1.1.2 root 864: Tcl_CreateObjCommand(interp, "Gen_VDPDescribe", Gen_VDPDescribe, NULL,
865: NULL);
1.1 root 866: Tcl_CreateObjCommand(interp, "Gen_SpriteList", Gen_SpriteList, NULL, NULL);
1.1.1.2 root 867: Tcl_CreateObjCommand(interp, "Gen_Initialised", Gen_Initialised, NULL,
868: NULL);
1.1 root 869: Tcl_CreateObjCommand(interp, "Gen_Reset", Gen_Reset, NULL, NULL);
870:
871: if ((visual = Tk_GetVisual(interp, mainwin, "truecolor 24", &depth,
1.1.1.2 root 872: &cmap)) == NULL) {
1.1 root 873: depth = 0;
874: }
875: LOG_VERBOSE(("Asked for depth 24, got depth %d", depth));
876: if (depth != 16 && depth != 24) {
877: if ((visual = Tk_GetVisual(interp, mainwin, "pseudocolor 8", &depth,
1.1.1.2 root 878: NULL)) == NULL)
879: ui_err("%s: GetVisual failed: %s", argv[0],
880: Tcl_GetStringResult(interp));
1.1 root 881: if (depth != 8)
1.1.1.2 root 882: ui_err("%s: Depth is %d (we want 8, e.g. 256 colours).", argv[0],
883: depth);
1.1 root 884: if ((cmap = Tk_GetColormap(interp, mainwin, "new")) == 0)
885: ui_err("%s: Unable to create new colormap.", argv[0]);
886: if (Tk_SetWindowVisual(mainwin, visual, 8, cmap) != 1)
887: ui_err("%s: Unable to set window visual/colormap.", argv[0]);
888: if (XAllocColorCells(ui_display, cmap, True, plane_masks, 0,
1.1.1.2 root 889: colours, 32) == 0)
1.1 root 890: ui_err("%s: Unable to allocate colors.", argv[0]);
891: for (i = 0; i < 32; i++) {
892: xcolor.pixel = i;
893: xcolor.flags = 0;
894: XQueryColor(ui_display, DefaultColormap(ui_display, ui_screenno),
1.1.1.2 root 895: &xcolor);
1.1 root 896: XStoreColor(ui_display, cmap, &xcolor);
897: }
898: if (XAllocColorCells(ui_display, cmap, True, plane_masks, 0,
1.1.1.2 root 899: colours, 64 * 3) == 0)
1.1 root 900: ui_err("%s: Unable to allocate colors.", argv[0]);
901: basepixel = colours[0];
902: LOG_VERBOSE(("UI: Base pixel %d", basepixel));
903: } else {
904: if (Tk_SetWindowVisual(mainwin, visual, depth, cmap) != 1)
905: ui_err("%s: Unable to set window visual/colormap.", argv[0]);
906: }
907:
1.1.1.2 root 908: if ((imagedata = malloc(320 * 240 * (depth / 8))) == NULL)
1.1 root 909: ui_err("%s: Out of memory!", argv[0]);
1.1.1.2 root 910: memset(imagedata, 0, 320 * 240 * (depth / 8));
1.1 root 911: if ((image = XCreateImage(ui_display, visual, depth, ZPixmap, 0,
1.1.1.2 root 912: imagedata, 320, 240, 8, 0)) == NULL) {
1.1 root 913: ui_err("%s: Unable to create image.", argv[0]);
914: }
915: /* XCreateImage is broken on my system - force these values */
1.1.1.2 root 916: image->bytes_per_line = 320 * (depth / 8);
1.1 root 917: image->bits_per_pixel = depth;
918: if (depth != 8) {
919: visual_bluemask = image->blue_mask;
920: visual_redmask = image->red_mask;
921: visual_greenmask = image->green_mask;
922: visual_bluepos = ui_topbit(visual_bluemask) - 2;
923: visual_redpos = ui_topbit(visual_redmask) - 2;
924: visual_greenpos = ui_topbit(visual_greenmask) - 2;
925: if (visual_bluepos == -1 || visual_redpos == -1 || visual_greenpos == -1) {
926: ui_err("%s: Bad colour masks (%x(%d),%x(%d),%x(%d)).",
1.1.1.2 root 927: argv[0], visual_redmask, visual_redpos,
928: visual_greenmask, visual_greenpos,
929: visual_bluemask, visual_bluepos);
1.1 root 930: }
931: }
932:
933: XInitImage(image);
934:
935: /* DGA stuff */
936:
937: ui_dga = 0;
938:
939: #ifdef XF86DGA
940: if (geteuid()) {
941: LOG_NORMAL(("%s: You are not root and so DGA is disabled.", argv[0]));
942: } else if (!XF86DGAQueryVersion(ui_display, &dga_major, &dga_minor)) {
943: LOG_NORMAL(("%s: XF86DGAQueryVersion failed", argv[0]));
944: } else if (!XF86DGAQueryExtension(ui_display, &dga_eventb, &dga_errorb)) {
945: LOG_NORMAL(("%s: XF86DGAQueryExtension failed", argv[0]));
946: } else if (!XF86DGAQueryDirectVideo(ui_display, ui_screenno, &dga_flags)) {
947: LOG_NORMAL(("%s: XF86DGAQueryDirectVideo failed", argv[0]));
948: } else if (!(dga_flags & XF86DGADirectPresent)) {
949: LOG_NORMAL(("%s: DGA Direct video support is not present", argv[0]));
950: } else if (!XF86DGAGetVideo(ui_display, ui_screenno, &dga_baseaddr,
1.1.1.2 root 951: &dga_width, &dga_banksize, &dga_memsize)) {
1.1 root 952: LOG_NORMAL(("%s: XF86DGAGetVideo failed", argv[0]));
953: } else if (!XF86DGAGetViewPortSize(ui_display, ui_screenno, &dga_xsize,
1.1.1.2 root 954: &dga_ysize)) {
1.1 root 955: LOG_NORMAL(("%s: XF86DGAGetViewPortsize failed", argv[0]));
956: } else {
957: ui_dga = 1;
1.1.1.2 root 958: dga_start = dga_baseaddr + ((depth / 8) *
959: (dga_xsize *
960: ((dga_ysize - (240 * scale)) / 2) +
961: ((dga_xsize - (320 * scale)) / 2)));
1.1 root 962: LOG_NORMAL(("DGA: Direct full-screen video enabled at "
1.1.1.2 root 963: "%08X (%d/%d) [%d x %d].", dga_baseaddr, dga_banksize,
964: dga_memsize, dga_xsize, dga_ysize));
1.1 root 965: }
966: if (!ui_dga) {
967: LOG_NORMAL(("DGA has been disabled, no full-screen facilities will "
1.1.1.2 root 968: "be available."));
1.1 root 969: }
970: #else
971: LOG_VERBOSE(("DGA: Not compiled in."));
972: #endif
973: if (setuid(getuid()))
974: ui_err("%s: Failed to setuid: %s", argv[0], strerror(errno));
975:
976: /* end DGA stuff */
977:
978: ui_updateint("debug", gen_debugmode);
979:
980: Tk_CreateEventHandler(mainwin, KeyPressMask | KeyReleaseMask,
1.1.1.2 root 981: ui_keypress, NULL);
1.1 root 982: Tk_CreateEventHandler(mainwin, EnterWindowMask | LeaveWindowMask,
1.1.1.2 root 983: ui_enterleave, NULL);
1.1 root 984:
985: if (argc == 2) {
1.1.1.2 root 986: if ((ui_initload = malloc(strlen(argv[1]) + 1)) == NULL) {
1.1 root 987: fprintf(stderr, "Out of memory\n");
988: return 1;
989: }
990: strcpy(ui_initload, argv[1]);
991: }
992: return 0;
993: }
994:
995: int ui_topbit(unsigned long int bits)
996: {
997: long int bit = 31;
1.1.1.2 root 998: unsigned long int mask = 1 << 31;
1.1 root 999:
1.1.1.2 root 1000: for (; bit >= 0; bit--, mask >>= 1) {
1.1 root 1001: if (bits & mask)
1002: return bit;
1003: }
1004: return -1;
1005: }
1006:
1007: void ui_final(void)
1008: {
1009: XAutoRepeatOn(ui_display);
1010: }
1011:
1.1.1.2 root 1012: void ui_enterleave(ClientData cd, XEvent * event)
1.1 root 1013: {
1.1.1.3 ! root 1014:
! 1015: (void)cd;
1.1 root 1016: if (event->type == EnterNotify) {
1017: XAutoRepeatOff(ui_display);
1018: } else {
1019: XAutoRepeatOn(ui_display);
1020: }
1021: }
1022:
1.1.1.2 root 1023: void ui_keypress(ClientData cd, XEvent * event)
1.1 root 1024: {
1025: char keysym = XLookupKeysym(&event->xkey, 0);
1026: int type = (event->type == KeyPress);
1027:
1.1.1.3 ! root 1028: (void)cd;
1.1 root 1029: LOG_DEBUG3(("KEY %d: %d", type, keysym));
1.1.1.2 root 1030: switch (keysym) {
1.1 root 1031: case 'a':
1032: case '1':
1033: case 'z':
1.1.1.2 root 1034: mem68k_cont[0].a = type;
1.1 root 1035: break;
1036: case 'b':
1037: case '2':
1038: case 's':
1039: case 'x':
1.1.1.2 root 1040: mem68k_cont[0].b = type;
1.1 root 1041: break;
1042: case 'c':
1043: case '3':
1044: case 'd':
1.1.1.2 root 1045: mem68k_cont[0].c = type;
1.1 root 1046: break;
1047: case 81:
1.1.1.2 root 1048: mem68k_cont[0].left = type;
1.1 root 1049: break;
1050: case 82:
1.1.1.2 root 1051: mem68k_cont[0].up = type;
1.1 root 1052: break;
1053: case 83:
1.1.1.2 root 1054: mem68k_cont[0].right = type;
1.1 root 1055: break;
1056: case 84:
1.1.1.2 root 1057: mem68k_cont[0].down = type;
1.1 root 1058: break;
1059: case 13:
1.1.1.2 root 1060: mem68k_cont[0].start = type;
1.1 root 1061: break;
1062: #ifdef XF86DGA
1063: case '#':
1064: if (type)
1065: ui_fullscreen(ui_dga_state ^ 1);
1066: break;
1067: #endif
1068: default:
1069: break;
1070: }
1071: }
1072:
1073: /*** ui_updateregs - update register information ***/
1074:
1075: void ui_updateregs(void)
1076: {
1077: int i, t;
1078: char val[256], var[256];
1079:
1080: for (t = 0; t < 2; t++) {
1081: for (i = 0; i < 8; i++) {
1.1.1.2 root 1082: sprintf(val, "%08X", regs.regs[t * 8 + i]);
1.1 root 1083: sprintf(var, "regs.%s%d", t ? "a" : "d", i);
1084: ui_updatestr(var, val);
1085: }
1086: }
1.1.1.2 root 1087: sprintf(val, "%08X", regs.pc);
1088: ui_updatestr("regs.pc", val);
1089: sprintf(val, "%04X", regs.sr.sr_int);
1090: ui_updatestr("regs.sr", val);
1091: sprintf(val, "%08X", regs.sp);
1092: ui_updatestr("regs.sp", val);
1.1 root 1093: ui_updateint("regs.s", regs.sr.sr_struct.s);
1094: ui_updateint("regs.x", regs.sr.sr_struct.x);
1095: ui_updateint("regs.n", regs.sr.sr_struct.n);
1096: ui_updateint("regs.z", regs.sr.sr_struct.z);
1097: ui_updateint("regs.v", regs.sr.sr_struct.v);
1098: ui_updateint("regs.c", regs.sr.sr_struct.c);
1099: ui_updateint("regs.frames", cpu68k_frames);
1100: ui_updateint("regs.clocks", cpu68k_clocks);
1101: }
1102:
1103: void ui_updatestr(char *var, char *val)
1104: {
1105: Tcl_Obj *valobj, *varobj;
1106:
1107: valobj = Tcl_NewStringObj(val, -1);
1108: Tcl_IncrRefCount(valobj);
1109: varobj = Tcl_NewStringObj(var, -1);
1110: Tcl_IncrRefCount(varobj);
1111:
1112: if (Tcl_ObjSetVar2(interp, varobj, NULL, valobj,
1.1.1.2 root 1113: TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
1.1 root 1114: LOG_CRITICAL(("Error setting %s", val));
1115: }
1116: Tcl_DecrRefCount(varobj);
1117: Tcl_DecrRefCount(valobj);
1118: }
1119:
1120: void ui_updateint(char *var, int val)
1121: {
1122: Tcl_Obj *valobj, *varobj;
1123:
1124: valobj = Tcl_NewIntObj(val);
1125: Tcl_IncrRefCount(valobj);
1126: varobj = Tcl_NewStringObj(var, -1);
1127: Tcl_IncrRefCount(varobj);
1128:
1129: if (Tcl_ObjSetVar2(interp, varobj, NULL, valobj,
1.1.1.2 root 1130: TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
1.1 root 1131: LOG_CRITICAL(("Error setting %s", val));
1132: }
1133: Tcl_DecrRefCount(varobj);
1134: Tcl_DecrRefCount(valobj);
1135: }
1136:
1137: /*** ui_loop - main UI loop ***/
1138:
1139: int ui_loop(void)
1140: {
1141: char *trace;
1142:
1143: ui_updateregs();
1144:
1145: /* Run Tcl script */
1146: if (Tcl_EvalFile(interp, FNAME_TCLSCRIPT) != TCL_OK) {
1147: LOG_CRITICAL(("error: %s", Tcl_GetStringResult(interp)));
1148: if ((trace = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY)) != NULL) {
1149: LOG_NORMAL(("TCL TRACE: %s", trace));
1150: }
1151: return 1;
1152: }
1153:
1154: gen_quit = 0;
1.1.1.2 root 1155: while (!gen_quit) {
1156: switch (state) {
1157: case 0: /* stopped */
1.1 root 1158: Tcl_DoOneEvent(TCL_ALL_EVENTS);
1159: break;
1.1.1.2 root 1160: case 1: /* paused */
1.1 root 1161: Tcl_DoOneEvent(TCL_ALL_EVENTS);
1162: break;
1.1.1.2 root 1163: case 2: /* playing */
1.1 root 1164: event_doframe();
1165: Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
1166: break;
1167: }
1168: }
1169: return 0;
1170: }
1171:
1172: /*** ui_loadimage - load ROM image ***/
1173:
1.1.1.2 root 1174: int ui_loadimage(Tcl_Interp * interp, const char *filename)
1.1 root 1175: {
1176: char *p;
1177:
1178: p = gen_loadimage(filename);
1.1.1.3 ! root 1179: if (!p)
! 1180: p = ui_setinfo(&gen_cartinfo);
1.1 root 1181: if (p) {
1182: Tcl_SetResult(interp, p, TCL_STATIC);
1183: return TCL_ERROR;
1184: }
1185: ui_updateregs();
1186: return TCL_OK;
1187: }
1188:
1189: /*** ui_loadsavepos - load saved position ***/
1190:
1.1.1.2 root 1191: int ui_loadsavepos(Tcl_Interp * interp, const char *filename)
1.1 root 1192: {
1.1.1.3 ! root 1193: if ((state_loadfile(filename)) != 0) {
! 1194: Tcl_SetResult(interp, "error loading file", TCL_STATIC);
1.1 root 1195: return TCL_ERROR;
1196: }
1197: return TCL_OK;
1198: }
1199:
1200: /*** ui_setinfo - set information window with name/copyright/etc ***/
1201:
1.1.1.3 ! root 1202: static char *ui_setinfo(t_cartinfo * cartinfo)
1.1 root 1203: {
1204: char buffer[128];
1205:
1206: if (ui_setstr("i_console", cartinfo->console) ||
1207: ui_setstr("i_copyright", cartinfo->copyright) ||
1208: ui_setstr("i_name_domestic", cartinfo->name_domestic) ||
1209: ui_setstr("i_name_overseas", cartinfo->name_overseas) ||
1210: ui_setstr("i_version", cartinfo->version) ||
1211: ui_setstr("i_memo", cartinfo->memo))
1212: return "Unable to set tcl variables";
1213: sprintf(buffer, "%x", cartinfo->checksum);
1214: if (ui_setstr("i_checksum", buffer))
1215: return "Unable to set checksum tcl variable";
1216: if (cartinfo->prodtype == pt_game) {
1217: if (ui_setstr("i_prodtype", "Game"))
1218: return "Unable to set checksum tcl variable";
1219: } else if (cartinfo->prodtype == pt_education) {
1220: if (ui_setstr("i_prodtype", "Education"))
1221: return "Unable to set checksum tcl variable";
1222: } else {
1223: if (ui_setstr("i_prodtype", "Unknown"))
1224: return "Unable to set checksum tcl variable";
1225: }
1226: return NULL;
1227: }
1228:
1229: /*** ui_checkpalcache - make palette cache up-to-date ***/
1230:
1231: void ui_checkpalcache(int flag)
1232: {
1233: unsigned int col;
1234: uint8 *p;
1235:
1236: /* this code requires that there be at least 4 bits per colour, that
1237: is, three bits that come from the console's palette, and one more bit
1238: when we do a dim or bright colour, i.e. this code works with 12bpp
1239: upwards */
1240:
1241: for (col = 0; col < 64; col++) {
1242: if (!flag && !vdp_cramf[col])
1243: continue;
1244: vdp_cramf[col] = 0;
1.1.1.2 root 1245: p = (uint8 *)vdp_cram + 2 * col;
1246: ui_palcache[col] =
1247: (((p[0] >> 1) & 7) << visual_bluepos) |
1248: (((p[1] >> 1) & 7) << visual_redpos) |
1249: (((p[1] >> 5) & 7) << visual_greenpos);
1250: ui_palcache[col + 64] =
1251: (((p[0] >> 1) & 7) << (visual_bluepos - 1)) |
1252: (((p[1] >> 1) & 7) << (visual_redpos - 1)) |
1253: (((p[1] >> 5) & 7) << (visual_greenpos - 1)) |
1254: (4 << visual_bluepos) | (4 << visual_redpos) | (4 << visual_greenpos);
1255: ui_palcache[col + 128] =
1256: (((p[0] >> 1) & 7) << (visual_bluepos - 1)) |
1257: (((p[1] >> 1) & 7) << (visual_redpos - 1)) |
1258: (((p[1] >> 5) & 7) << (visual_greenpos - 1));
1.1 root 1259: }
1260: }
1261:
1262: /*** ui_line - it is time to render a line ***/
1263:
1.1.1.3 ! root 1264: void ui_line(int line)
1.1.1.2 root 1265: {
1.1 root 1266: static uint8 gfx[320];
1.1.1.3 ! root 1267: char *p;
1.1 root 1268: int lineoffset;
1269:
1270: if (ui_vdpsimple)
1271: return;
1.1.1.3 ! root 1272: if (line < 0 || line >= (int)vdp_vislines)
! 1273: return;
1.1 root 1274:
1275: #ifdef XF86DGA
1276: if (ui_dga_state) {
1.1.1.2 root 1277: lineoffset = dga_xsize * (depth / 8);
1278: p = dga_start + line * lineoffset * scale;
1.1 root 1279: } else {
1.1.1.2 root 1280: lineoffset = 320 * (depth / 8) * scale;
1281: p = imagedata + line * lineoffset * scale;
1.1 root 1282: }
1283: #else
1.1.1.2 root 1284: lineoffset = 320 * (depth / 8) * scale;
1285: p = imagedata + line * lineoffset * scale;
1.1 root 1286: #endif
1287:
1288: if (cpu68k_frames % frameskip != 0)
1289: return;
1290:
1291: LOG_DEBUG2(("line %d: ", line));
1.1.1.2 root 1292: switch ((vdp_reg[12] >> 1) & 3) {
1293: case 0: /* normal */
1294: case 1: /* interlace simply doubled up */
1295: case 2: /* invalid */
1.1 root 1296: vdp_renderline(line, gfx, 0);
1.1.1.2 root 1297: break;
1298: case 3: /* interlace with double resolution */
1299: vdp_renderline(line, gfx, vdp_oddframe);
1300: break;
1301: }
1.1 root 1302: if (scale == 2 && smooth) {
1303: ui_convertdata_smooth(gfx, p, 320, lineoffset, depth);
1304: } else {
1305: ui_convertdata(gfx, p, 320, lineoffset, scale, depth, basepixel);
1306: }
1307: }
1308:
1.1.1.2 root 1309: void
1310: ui_convertdata(uint8 *indata, uint8 *outdata, unsigned int pixels,
1311: unsigned int lineoffset, unsigned int scale,
1312: unsigned int depth, unsigned int basepixel)
1.1 root 1313: {
1314: char *p, *pp;
1315: unsigned int ui;
1316: unsigned int t, s;
1317: uint32 data;
1318:
1319: if (depth == 8) {
1320: if (scale == 1) {
1.1.1.2 root 1321: /* not scaled, 8bpp */
1322: for (ui = 0; ui < pixels; ui++) {
1323: outdata[ui] = indata[ui] + basepixel;
1324: }
1.1 root 1325: } else {
1326: /* scaled, 8bpp */
1327: p = outdata;
1.1.1.2 root 1328: for (ui = 0; ui < pixels; ui++, p += ui * scale) {
1329: pp = p;
1330: for (s = 0; s < scale; s++, pp += lineoffset) {
1.1 root 1331: for (t = 0; t < scale; t++) {
1332: pp[t] = indata[ui] + basepixel;
1.1.1.2 root 1333: }
1334: }
1.1 root 1335: }
1336: }
1337: } else {
1338: ui_checkpalcache(0);
1339: if (scale == 1) {
1340: if (depth == 16) {
1.1.1.2 root 1341: /* not scaled, 16bpp */
1342: for (ui = 0; ui < pixels; ui++) {
1343: data = ui_palcache[indata[ui]];
1344: ((uint16 *)outdata)[ui] = data; /* already in local endian */
1345: }
1.1 root 1346: } else if (depth == 24) {
1.1.1.2 root 1347: /* not scaled, 24bpp */
1348: p = outdata;
1349: for (ui = 0; ui < pixels; ui++, p += 3) {
1350: data = ui_palcache[indata[ui]];
1.1 root 1351: #ifdef WORDS_BIGENDIAN
1.1.1.2 root 1352: p[0] = (uint8)(data >> 16);
1353: p[1] = (uint8)(data >> 8);
1354: p[2] = (uint8)(data);
1.1 root 1355: #else
1.1.1.2 root 1356: p[0] = (uint8)(data);
1357: p[1] = (uint8)(data >> 8);
1358: p[2] = (uint8)(data >> 16);
1.1 root 1359: #endif
1.1.1.2 root 1360: }
1.1 root 1361: } else {
1362: ui_err("unknown depth %d", depth);
1363: }
1364: } else if (scale == 2) {
1365: if (depth == 16) {
1.1.1.2 root 1366: /* scaled by 2, 16bpp */
1367: p = outdata;
1368: for (ui = 0; ui < pixels; ui++, p += 4) {
1369: data = ui_palcache[indata[ui]];
1370: ((uint16 *)p)[0] = data; /* already in local endian */
1371: ((uint16 *)p)[1] = data;
1372: ((uint16 *)(p + lineoffset))[0] = data;
1373: ((uint16 *)(p + lineoffset))[1] = data;
1374: }
1.1 root 1375: } else if (depth == 24) {
1.1.1.2 root 1376: /* scaled by 2, 24bpp */
1377: p = outdata;
1378: for (ui = 0; ui < pixels; ui++, p += 6) {
1379: data = ui_palcache[indata[ui]];
1.1 root 1380: #ifdef WORDS_BIGENDIAN
1.1.1.2 root 1381: p[0] = (uint8)(data >> 16);
1382: p[3] = (uint8)(data >> 16);
1383: p[lineoffset + 0] = (uint8)(data >> 16);
1384: p[lineoffset + 3] = (uint8)(data >> 16);
1385: p[1] = (uint8)(data >> 8);
1386: p[4] = (uint8)(data >> 8);
1387: p[lineoffset + 1] = (uint8)(data >> 8);
1388: p[lineoffset + 4] = (uint8)(data >> 8);
1389: p[2] = (uint8)(data);
1390: p[5] = (uint8)(data);
1391: p[lineoffset + 2] = (uint8)(data);
1392: p[lineoffset + 5] = (uint8)(data);
1.1 root 1393: #else
1.1.1.2 root 1394: p[0] = (uint8)(data);
1395: p[3] = (uint8)(data);
1396: p[lineoffset + 0] = (uint8)(data);
1397: p[lineoffset + 3] = (uint8)(data);
1398: p[1] = (uint8)(data >> 8);
1399: p[4] = (uint8)(data >> 8);
1400: p[lineoffset + 1] = (uint8)(data >> 8);
1401: p[lineoffset + 4] = (uint8)(data >> 8);
1402: p[2] = (uint8)(data >> 16);
1403: p[5] = (uint8)(data >> 16);
1404: p[lineoffset + 2] = (uint8)(data >> 16);
1405: p[lineoffset + 5] = (uint8)(data >> 16);
1.1 root 1406: #endif
1.1.1.2 root 1407: }
1.1 root 1408: } else {
1409: ui_err("unknown depth %d", depth);
1410: }
1411: } else {
1412: /* scaled by more than 2 */
1413: for (ui = 0; ui < pixels; ui++) {
1.1.1.2 root 1414: data = ui_palcache[indata[ui]];
1415: p = outdata + ui * (depth / 8) * scale;
1416: for (s = 0; s < scale; s++, p += lineoffset) {
1417: for (t = 0; t < scale; t++) {
1418: if (depth == 16) {
1419: ((uint16 *)p)[t] = data; /* already in local endian */
1420: } else if (depth == 24) {
1421: pp = p + t * 3;
1.1 root 1422: #ifdef WORDS_BIGENDIAN
1.1.1.2 root 1423: pp[0] = (uint8)(data >> 16);
1424: pp[1] = (uint8)(data >> 8);
1425: pp[2] = (uint8)(data);
1.1 root 1426: #else
1.1.1.2 root 1427: pp[0] = (uint8)(data);
1428: pp[1] = (uint8)(data >> 8);
1429: pp[2] = (uint8)(data >> 16);
1.1 root 1430: #endif
1.1.1.2 root 1431: } else {
1.1 root 1432: ui_err("unknown depth %d", depth);
1433: }
1.1.1.2 root 1434: }
1435: }
1.1 root 1436: }
1437: }
1438: }
1439: }
1440:
1.1.1.2 root 1441: void
1442: ui_convertdata_smooth(uint8 *indata, uint8 *outdata, unsigned int pixels,
1443: unsigned int lineoffset, unsigned int depth)
1.1 root 1444: {
1.1.1.3 ! root 1445: char *p;
1.1 root 1446: unsigned int ui;
1447: uint32 data1, data2, datam;
1448:
1449: ui_checkpalcache(0);
1450: if (depth == 16) {
1451: /* scaled by 2, 16bpp */
1452: p = outdata;
1453: data1 = ui_palcache[indata[0]];
1.1.1.2 root 1454: for (ui = 0; ui < pixels - 1; ui++, p += 4) {
1455: data2 = ui_palcache[indata[ui + 1]];
1.1 root 1456: datam = (((((data1 & visual_redmask) +
1.1.1.2 root 1457: (data2 & visual_redmask)) >> 1) & visual_redmask) |
1458: ((((data1 & visual_greenmask) +
1459: (data2 & visual_greenmask)) >> 1) & visual_greenmask) |
1460: ((((data1 & visual_bluemask) +
1461: (data2 & visual_bluemask)) >> 1) & visual_bluemask));
1.1 root 1462: ((uint16 *)p)[0] = data1; /* already in local endian */
1463: ((uint16 *)p)[1] = datam;
1.1.1.2 root 1464: ((uint16 *)(p + lineoffset))[0] = data1;
1465: ((uint16 *)(p + lineoffset))[1] = datam;
1.1 root 1466: data1 = data2;
1467: }
1468: } else {
1469: /* scaled by 2, 24bpp */
1470: p = outdata;
1471: data1 = ui_palcache[indata[0]];
1.1.1.2 root 1472: for (ui = 0; ui < pixels; ui++, p += 6) {
1473: data2 = ui_palcache[indata[ui + 1]];
1.1 root 1474: datam = (((((data1 & visual_redmask) +
1.1.1.2 root 1475: (data2 & visual_redmask)) >> 1) & visual_redmask) |
1476: ((((data1 & visual_greenmask) +
1477: (data2 & visual_greenmask)) >> 1) & visual_greenmask) |
1478: ((((data1 & visual_bluemask) +
1479: (data2 & visual_bluemask)) >> 1) & visual_bluemask));
1.1 root 1480: #ifdef WORDS_BIGENDIAN
1.1.1.2 root 1481: p[0] = (uint8)(data1 >> 16);
1482: p[lineoffset + 0] = (uint8)(data1 >> 16);
1483: p[lineoffset + 3] = (uint8)(datam >> 16);
1484: p[3] = (uint8)(datam >> 16);
1485: p[1] = (uint8)(data1 >> 8);
1486: p[lineoffset + 1] = (uint8)(data1 >> 8);
1487: p[lineoffset + 4] = (uint8)(datam >> 8);
1488: p[4] = (uint8)(datam >> 8);
1489: p[2] = (uint8)(data1);
1490: p[lineoffset + 2] = (uint8)(data1);
1491: p[lineoffset + 5] = (uint8)(datam);
1492: p[5] = (uint8)(datam);
1.1 root 1493: #else
1.1.1.2 root 1494: p[0] = (uint8)(data1);
1495: p[lineoffset + 0] = (uint8)(data1);
1496: p[lineoffset + 3] = (uint8)(datam);
1497: p[3] = (uint8)(datam);
1498: p[1] = (uint8)(data1 >> 8);
1499: p[lineoffset + 1] = (uint8)(data1 >> 8);
1500: p[lineoffset + 4] = (uint8)(datam >> 8);
1501: p[4] = (uint8)(datam >> 8);
1502: p[2] = (uint8)(data1 >> 16);
1503: p[lineoffset + 2] = (uint8)(data1 >> 16);
1504: p[lineoffset + 5] = (uint8)(datam >> 16);
1505: p[5] = (uint8)(datam >> 16);
1.1 root 1506: #endif
1507: data1 = data2;
1508: }
1509: }
1510: }
1511:
1512: /*** ui_endfield - end of field reached ***/
1513:
1514: void ui_endfield(void)
1515: {
1516: ui_endframe();
1517: }
1518:
1519: /*** ui_endframe - end of frame reached ***/
1520:
1521: void ui_endframe(void)
1522: {
1.1.1.3 ! root 1523: int i;
1.1 root 1524: XColor xcolor;
1.1.1.2 root 1525: static uint8 gfx[(320 + 16) * (240 + 16)];
1.1 root 1526: char *p, *framestart;
1527: unsigned int lineoffset, line;
1528:
1529: if (cpu68k_frames % frameskip != 0)
1530: return;
1531:
1532: if (ui_vdpsimple) {
1533: /* simple mode - entire frame done here */
1.1.1.2 root 1534: framestart = gfx + (8 * 320) + 8;
1535: vdp_renderframe(framestart, 320 + 16); /* plot frame */
1.1 root 1536: #ifdef XF86DGA
1537: if (ui_dga_state) {
1.1.1.2 root 1538: lineoffset = dga_xsize * (depth / 8);
1.1 root 1539: p = dga_start;
1540: } else {
1.1.1.2 root 1541: lineoffset = 320 * (depth / 8) * scale;
1.1 root 1542: p = imagedata;
1543: }
1544: #else
1.1.1.2 root 1545: lineoffset = 320 * (depth / 8) * scale;
1.1 root 1546: p = imagedata;
1547: #endif
1548: for (line = 0; line < 224; line++) {
1549: if (scale == 2 && smooth) {
1.1.1.2 root 1550: ui_convertdata_smooth(framestart + (320 + 16) * line,
1551: p + lineoffset * line * scale, 320,
1552: lineoffset, depth);
1.1 root 1553: } else {
1.1.1.2 root 1554: ui_convertdata(framestart + (320 + 16) * line,
1555: p + lineoffset * line * scale, 320, lineoffset,
1556: scale, depth, basepixel);
1.1 root 1557: }
1558: }
1559: }
1560: if (!ui_dga_state) {
1561: /* if ui_dga_state state is set, data has already gone to screen */
1562: if (!gc)
1563: gc = XCreateGC(ui_display, Tk_WindowId(mainwin), 0, NULL);
1.1.1.2 root 1564: XPutImage(ui_display,
1565: Tk_WindowId(Tk_NameToWindow(interp, ".main", mainwin)),
1566: gc, image, 0, 0, 0, 0, 320 * scale, 240 * scale);
1.1 root 1567: }
1568: if (depth == 8) {
1569: for (i = 0; i < 64; i++) {
1570: if (vdp_cramf[i]) {
1.1.1.2 root 1571: xcolor.pixel = basepixel + i;
1572: xcolor.flags = DoRed | DoGreen | DoBlue;
1573: xcolor.blue = ((((uint8 *)vdp_cram)[2 * i]) & (7 << 1)) << 12;
1574: xcolor.red = ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 1)) << 12;
1575: xcolor.green = ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 5)) << 8;
1576: XStoreColor(ui_display, cmap, &xcolor);
1577: xcolor.pixel = basepixel + i + 64;
1578: xcolor.blue =
1579: 1 << 15 | ((((uint8 *)vdp_cram)[2 * i]) & (7 << 1)) << 11;
1580: xcolor.red =
1581: 1 << 15 | ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 1)) << 11;
1582: xcolor.green =
1583: 1 << 15 | ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 5)) << 7;
1584: XStoreColor(ui_display, cmap, &xcolor);
1585: xcolor.pixel = basepixel + i + 128;
1586: xcolor.blue = ((((uint8 *)vdp_cram)[2 * i]) & (7 << 1)) << 11;
1587: xcolor.red = ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 1)) << 11;
1588: xcolor.green = ((((uint8 *)vdp_cram)[2 * i + 1]) & (7 << 5)) << 7;
1589: XStoreColor(ui_display, cmap, &xcolor);
1590: vdp_cramf[i] = 0;
1.1 root 1591: }
1592: }
1593: }
1594: }
1595:
1596: #ifdef XF86DGA
1597: void ui_fullscreen(int onoff)
1598: {
1599: static int forkflag = 0;
1600: int i;
1601:
1602: ui_dga_state = 0;
1603:
1604: if (!ui_dga) {
1.1.1.2 root 1605: LOG_CRITICAL(("DGA has been disabled, see error message " "on startup."));
1.1 root 1606: return;
1607: }
1608: if (onoff) {
1609: if (!XF86DGADirectVideo(ui_display, ui_screenno, XF86DGADirectGraphics)) {
1610: LOG_CRITICAL(("Switch to DGA direct video failed"));
1611: return;
1612: }
1613: if (!XF86DGASetViewPort(ui_display, ui_screenno, 0, 0)) {
1614: LOG_CRITICAL(("Setting of DGA view port failed"));
1615: return;
1616: }
1617: memset(dga_baseaddr, 0, dga_banksize);
1618: ui_dga_state = 1;
1619: } else {
1620: if (!XF86DGADirectVideo(ui_display, ui_screenno, 0)) {
1621: LOG_CRITICAL(("Switch out of DGA mode failed"));
1622: return;
1623: }
1624: }
1625: }
1626: #endif
1627:
1628: /*** logging functions ***/
1629:
1630: /* logging is done this way because this was the best I could come up with
1631: whilst battling with macros that can only take fixed numbers of arguments */
1632:
1633: #define LOG_FUNC(name,level,txt) void ui_log_ ## name ## (const char *text, ...) \
1634: { \
1635: va_list ap; \
1636: if (gen_loglevel >= level) { \
1637: printf("%s (%05X) ", txt, cpu68k_clocks); \
1638: va_start(ap, text); \
1639: vprintf(text, ap); \
1640: va_end(ap); \
1641: putchar(10); \
1642: } \
1643: }
1644:
1.1.1.2 root 1645: LOG_FUNC(debug3, 7, "DEBG ");
1646: LOG_FUNC(debug2, 6, "DEBG ");
1647: LOG_FUNC(debug1, 5, "DEBG ");
1648: LOG_FUNC(user, 4, "USER ");
1649: LOG_FUNC(verbose, 3, "---- ");
1650: LOG_FUNC(normal, 2, "---- ");
1.1 root 1651: LOG_FUNC(critical, 1, "CRIT ");
1.1.1.2 root 1652: LOG_FUNC(request, 0, "---- ");
1.1 root 1653:
1654: /*** ui_err - log error message and quit ***/
1655:
1656: void ui_err(const char *text, ...)
1657: {
1658: va_list ap;
1659:
1660: printf("ERROR: ");
1661:
1662: va_start(ap, text);
1663: vfprintf(stderr, text, ap);
1664: va_end(ap);
1665: putc(10, stderr);
1666: exit(1);
1667: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.