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