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