#include <stdio.h> #include <malloc.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include "system.h" #include "cpu.h" #include "screen.h" #include "keyboard.h" #include "atom.h" #define WIDTH 256 #define HEIGHT 192 static Display *display; static Screen *screen; static Window window; static Visual *visual; static XComposeStatus keyboard_status; static XImage *image; static GC gc; bool need_to_refresh = FALSE; static int colortable[4] = { 0x000000, 0xff0000, 0x00ff00, 0xffffff }; static int colours[4]; static bool mode; static int xlen, /* number of pixels in x direction */ xpix, /* size of a pixel in x direction */ ylen, /* number of pizels in y direction */ ypix, /* size of a pixel in y direction */ xlen8, /* number of bytes for one line */ len8, /* number of bytes in the whole screen */ color; /* 8: black/white, 4: color graphics */ void init_screen() { int i; XSetWindowAttributes xswda; XGCValues xgcvl; int depth; char *data; int offset = 0; int bitmap_pad = 8; int bytes_per_line = 0; display = XOpenDisplay (NULL); if (!display) { printf ("Failed to open display\n"); exit (1); } screen = XDefaultScreenOfDisplay (display); if (!screen) { printf ("Unable to get screen\n"); exit (1); } depth = XDefaultDepthOfScreen (screen); xswda.event_mask = KeyPress | KeyRelease | ExposureMask | EnterWindowMask | LeaveWindowMask; window = XCreateWindow (display, XRootWindowOfScreen(screen), 50, 50, WIDTH, HEIGHT, 3, depth, InputOutput, visual, CWEventMask | CWBackPixel, &xswda); XStoreName (display, window, TITLE); for (i=0;i<4;i++) { XColor colour; int rgb = colortable[i]; int status; colour.red = (rgb & 0x00ff0000) >> 8; colour.green = (rgb & 0x0000ff00); colour.blue = (rgb & 0x000000ff) << 8; status = XAllocColor (display, XDefaultColormapOfScreen(screen), &colour); colours[i] = colour.pixel; } xgcvl.background = colours[0]; xgcvl.foreground = colours[3]; gc = XCreateGC (display, window, GCForeground | GCBackground, &xgcvl); XMapWindow (display, window); XSync (display, False); data = malloc (WIDTH * HEIGHT); if (!data) { printf ("Failed to allocate space for image\n"); exit (1); } image = XCreateImage (display, visual, depth, ZPixmap, offset, data, WIDTH, HEIGHT, bitmap_pad, bytes_per_line); if (!image) { printf ("Failed to allocate image\n"); exit (1); } mode = 1; set_mode(0, 1); SetMemory(0x8000, 0x81FF, VIDEO); } void exit_screen() { XSync (display, True); XDestroyImage (image); XUnmapWindow (display, window); XDestroyWindow (display, window); XCloseDisplay (display); } void refresh_screen() { XPutImage (display, window, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT); } void update_screen() { if (need_to_refresh) { XPutImage (display, window, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT); need_to_refresh = FALSE; } } void atom_hardware (void) { while (XEventsQueued (display, QueuedAfterFlush) > 0) { XEvent xevent; XNextEvent (display, &xevent); switch ( xevent.type ) { case Expose : refresh_screen(); break; case KeyPress : handle_key (( XKeyEvent* ) &xevent, TRUE ); break; case KeyRelease : handle_key (( XKeyEvent* ) &xevent, FALSE ); break; case EnterNotify : XAutoRepeatOff ( display ); XFlush ( display ); break; case LeaveNotify : XAutoRepeatOn ( display ); XFlush ( display ); break; default : /* * All other events are masked out, so this should * barf big-time. */ break; } } } void set_mode(UBYTE graphic, SBYTE graphic_mode) { /* CLEAR 0 is mapped to text mode, with cursor off, uses the graphical characters */ if (graphic) { int x,y,i,b; if (mode == graphic_mode) return; mode = graphic_mode; switch(mode) { case 0: xlen = 64; ylen = 64; color = 4; break; /* CLEAR 1a */ case 1: xlen = 128; ylen = 64; color = 8; break; /* CLEAR 1 */ case 2: xlen = 128; ylen = 64; color = 4; break; /* CLEAR 2a */ case 3: xlen = 128; ylen = 96; color = 8; break; /* CLEAR 2 */ case 4: xlen = 128; ylen = 96; color = 4; break; /* CLEAR 3a */ case 5: xlen = 128; ylen = 192; color = 8; break; /* CLEAR 3 */ case 6: xlen = 128; ylen = 192; color = 4; break; /* CLEAR 4a */ case 7: xlen = 256; ylen = 192; color = 8; break; /* CLEAR 4 */ } xpix = 256 / xlen; ypix = 192 / ylen; xlen8 = xlen / color; len8 = xlen8 * ylen; printf("mode %d, xlen %d, ylen %d, xpix %d, ypix %d, xlen8 %d\n", mode, xlen, ylen, xpix, ypix, xlen8); SetMemory(0x8000, 0x7fff + len8, VIDEO); SetMemory(0x8000 + len8, 0x9800, RAM); b = 0x8000; for (y = 0; y < 192; y += ypix) { x = 0; for (i = 0; i < xlen8; i++, b++) { int v = memory[b]; int k; if (color == 4) for (k = 6; k >= 0; k -= 2) { int x2, y2, c = colours[(v >> k) & 3]; for (x2 = 0; x2 < xpix; x2++, x++) for (y2 = 0; y2 < ypix; y2++) XPutPixel (image, x, y + y2, c); } else for (k = 7; k >= 0; k--) { int x2, y2, c = colours[((v >> k) & 1) ? 3 : 0]; for (x2 = 0; x2 < xpix; x2++, x++) for (y2 = 0; y2 < ypix; y2++) XPutPixel (image, x, y + y2, c); } } } } else { int x, y, b; if (mode == -1) return; mode = -1; SetMemory(0x8000, 0x81ff, VIDEO); SetMemory(0x8200, 0x9800, RAM); b = 0x8000; for (y = 0; y < 192; y += 12) for (x = 0; x < 256; x += 8, b++) draw_character(x, y, memory[b]); } need_to_refresh = TRUE; /* XPutImage (display, window, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT); */ } UBYTE char_rep[64][7] = { { 14,17, 1,13,21,21,14 }, { 4,10,17,17,31,17,17 }, { 30, 9, 9,14, 9, 9,30 }, { 14,17,16,16,16,17,14 }, { 30, 9, 9, 9, 9, 9,30 }, { 31,16,16,28,16,16,31 }, { 31,16,16,30,16,16,16 }, { 15,16,16,19,17,17,15 }, { 17,17,17,31,17,17,17 }, { 14, 4, 4, 4, 4, 4,14 }, { 1, 1, 1,17,17,10, 4 }, { 17,18,20,24,24,20,18 }, { 16,16,16,16,16,16,31 }, { 17,27,21,17,17,17,17 }, { 17,25,21,19,17,17,17 }, { 14,17,17,17,17,17,14 }, { 30,17,17,30,16,16,16 }, { 14,17,17,17,21,18,13 }, { 30,17,17,30,20,18,17 }, { 14,17, 8, 4, 2,17,14 }, { 31, 4, 4, 4, 4, 4, 4 }, { 17,17,17,17,17,17,14 }, { 17,17,17,17,10,10, 4 }, { 17,17,17,17,21,27,17 }, { 17,17,10, 4,10,17,17 }, { 17,17,10, 4, 4, 4, 4 }, { 31, 1, 2, 4, 8,16,31 }, { 14, 8, 8, 8, 8, 8,14 }, { 16,16, 8, 4, 2, 1, 1 }, { 14, 2, 2, 2, 2, 2,14 }, { 4,14,31, 4, 4, 4, 4 }, { 0, 4, 8,31, 8, 4, 0 }, { 0, 0, 0, 0, 0, 0, 0 }, { 4, 4, 4, 4, 4, 0, 4 }, { 10,10, 0, 0, 0, 0, 0 }, { 10,10,27, 0,27,10,10 }, { 4,15,16,14, 1,30, 4 }, { 25,25, 2, 4, 8,19,19 }, { 8,20,20, 9,22,22, 9 }, { 4, 4, 0, 0, 0, 0, 0 }, { 2, 4, 8, 8, 8, 4, 2 }, { 8, 4, 2, 2, 2, 4, 8 }, { 0, 4,14,31,14, 4, 0 }, { 0, 4, 4,31, 4, 4, 0 }, { 0, 0, 0, 6, 6, 2, 4 }, { 0, 0, 0,31, 0, 0, 0 }, { 0, 0, 0, 0, 0, 4, 4 }, { 1, 1, 2, 4, 8,16,16 }, { 4,10,10,10,10,10, 4 }, { 4,12, 4, 4, 4, 4,14 }, { 14,17, 1,14,16,16,31 }, { 14,17, 1, 6, 1,17,14 }, { 2, 6,10,31, 2, 2, 2 }, { 31,16,30, 1, 1,17,14 }, { 14,16,16,30,17,17,14 }, { 31, 1, 2, 4, 8,16,16 }, { 14,17,17,14,17,17,14 }, { 14,17,17,15, 1, 1,14 }, { 0, 0, 4, 0, 4, 0, 0 }, { 6, 6, 0, 6, 6, 2, 4 }, { 2, 4, 8,16, 8, 4, 2 }, { 0, 0,31, 0,31, 0, 0 }, { 16, 8, 4, 2, 4, 8,16 }, { 4,10, 2, 4, 4, 0, 4 }, }; static void draw_char(int x0, int y, UBYTE ch, UBYTE bl, UBYTE wh) { int i, x, j, x2 = x0 + 2, x8 = x0 + 8; UBYTE *ch_rep = char_rep[ch]; for (i = 0; i < 3; i++, y++) for (x = x0; x < x8; x++) XPutPixel (image, x, y, bl); for (i = 0; i < 7; i++, y++, ch_rep++) { for (x = x0; x < x2; x++) XPutPixel (image, x, y, bl); for (j = 4; j >= 0; j--, x++) XPutPixel (image, x, y, ((*ch_rep >> j) & 1) ? wh : bl); XPutPixel (image, x, y, bl); } for (i = 0; i < 2; i++, y++) for (x = x0; x < x8; x++) XPutPixel (image, x, y, bl); } static void draw_gr(int x, int y, UBYTE bl, UBYTE wh) { int i; for (i = 0; i < 2; i++) { XPutPixel (image, x, y, bl); XPutPixel (image, x + 1, y, wh); XPutPixel (image, x + 2, y, bl); XPutPixel (image, x + 3, y, wh); y++; XPutPixel (image, x, y, wh); XPutPixel (image, x + 1, y, wh); XPutPixel (image, x + 2, y, wh); XPutPixel (image, x + 3, y, wh); y++; } } static void draw_graph(int x, int y, UBYTE ch, UBYTE bl, UBYTE wh) { int v; v = ch & 32; draw_gr(x, y, v ? bl : colours[0], v ? wh : colours[0]); v = ch & 16; draw_gr(x + 4, y, v ? bl : colours[0], v ? wh : colours[0]); y += 4; v = ch & 8; draw_gr(x, y, v ? bl : colours[0], v ? wh : colours[0]); v = ch & 4; draw_gr(x + 4, y, v ? bl : colours[0], v ? wh : colours[0]); y += 4; v = ch & 2; draw_gr(x, y, v ? bl : colours[0], v ? wh : colours[0]); v = ch & 1; draw_gr(x + 4, y, v ? bl : colours[0], v ? wh : colours[0]); } void draw_character(int x, int y, UBYTE ch) { if (ch < 64) draw_char(x, y, ch, colours[0], colours[3]); else if (ch < 128) draw_graph(x, y, ch, colours[3], colours[3]); else if (ch < 192) draw_char(x, y, ch - 128, colours[3], colours[0]); else draw_graph(x, y, ch, colours[3], colours[0]); } void update_video(UWORD addr, UBYTE v) { UWORD pos = addr - 0x8000; if (memory[addr] == v) return; memory[addr] = v; if (mode == -1) { int x = (pos % 32) * 8, y = (pos / 32) * 12; draw_character(x, y, v); /* copy [x, x + 7] [y, y + 11] */ XPutImage (display, window, gc, image, x, y, x, y, 8, 12); } else { int xb = pos % xlen8, /* x pos in bytes */ xo = xb * color * xpix, /* x pos on screen */ x = xo, yb = pos / xlen8, /* y pos in bytes */ yo = yb * ypix, /* y pos on screen */ y = yo, k; if (color == 4) for (k = 6; k >= 0; k -= 2) { int x2, y2, c = colours[(v >> k) & 3]; for (x2 = 0; x2 < xpix; x2++, x++) for (y2 = 0; y2 < ypix; y2++) XPutPixel (image, x, y + y2, c); } else for (k = 7; k >= 0; k--) { int x2, y2, c = colours[((v >> k) & 1) ? 3 : 0]; for (x2 = 0; x2 < xpix; x2++, x++) for (y2 = 0; y2 < ypix; y2++) XPutPixel (image, x, y + y2, c); } /* copy [xo, xo + color * xpix - 1] [y, y + ypix - 1] */ XPutImage (display, window, gc, image, xo, yo, xo, yo, color * xpix, ypix); } /* need_to_refresh = TRUE; */ /* XPutImage (display, window, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT); */ }