]> git.sur5r.net Git - cc65/commitdiff
Added a simulated console (memory mapped screen device, inpout device will
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 8 Oct 2009 18:33:50 +0000 (18:33 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Thu, 8 Oct 2009 18:33:50 +0000 (18:33 +0000)
follow).

git-svn-id: svn://svn.cc65.org/cc65/trunk@4351 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/sim65/chips/console.c [new file with mode: 0644]
src/sim65/chips/make/gcc.mak

diff --git a/src/sim65/chips/console.c b/src/sim65/chips/console.c
new file mode 100644 (file)
index 0000000..ad520c5
--- /dev/null
@@ -0,0 +1,637 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 console.c                                 */
+/*                                                                           */
+/*                  Console plugin for the sim65 simulator                   */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2003-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
+/* warranty.  In no event will the authors be held liable for any damages    */
+/* arising from the use of this software.                                    */
+/*                                                                           */
+/* Permission is granted to anyone to use this software for any purpose,     */
+/* including commercial applications, and to alter it and redistribute it    */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
+/* 1. The origin of this software must not be misrepresented; you must not   */
+/*    claim that you wrote the original software. If you use this software   */
+/*    in a product, an acknowledgment in the product documentation would be  */
+/*    appreciated but is not required.                                       */
+/* 2. Altered source versions must be plainly marked as such, and must not   */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+
+/* common */
+#include "attrib.h"
+
+/* sim65 */
+#include "chipif.h"
+
+
+
+/*****************************************************************************/
+/*                                   Forwards                                */
+/*****************************************************************************/
+
+
+
+static int ScreenInitChip (const struct SimData* Data);
+/* Initialize the chip, return an error code */
+
+static void* ScreenCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo);
+/* Create a new chip instance */
+
+static void ScreenDestroyInstance (void* Data);
+/* Destroy a chip instance */
+
+static void ScreenWrite (void* Data, unsigned Offs, unsigned char Val);
+/* Write user data */
+
+static unsigned char ScreenRead (void* Data, unsigned Offs);
+/* Read user data */
+
+static void ScreenDrawBorder (void);
+/* Draw the complete border */
+
+static void ScreenDrawChar (unsigned Offs);
+/* Draw one character at the given position */
+
+static void ScreenDrawAllChars (void);
+/* Redraw the complete interior screen */
+
+static void ScreenEventLoop (void);
+/* Get all waiting events and handle them */
+
+
+
+/*****************************************************************************/
+/*                                Global data                                */
+/*****************************************************************************/
+
+
+
+/* The SimData pointer we get when InitChip is called */
+static const SimData* Sim;
+
+/* Control data passed to the main program */
+static const struct ChipData CData[] = {
+    {
+        "VIDEOSCREEN",          /* Name of the chip */
+        CHIPDATA_TYPE_CHIP,     /* Type of the chip */
+        CHIPDATA_VER_MAJOR,     /* Version information */
+        CHIPDATA_VER_MINOR,
+
+        /* -- Exported functions -- */
+        ScreenInitChip,
+        ScreenCreateInstance,
+       ScreenDestroyInstance,
+        ScreenWrite,
+        ScreenWrite,
+        ScreenRead,
+        ScreenRead
+    },
+};
+
+/* Defines for console screen */
+static const XColor FgColor = {
+    0,  32*256, 141*256, 32*256, 0, 0          /* green */
+};
+static const XColor BgColor = {
+    0,  0*256, 0*256, 0*256, 0, 0               /* black */
+};
+
+
+/*****************************************************************************/
+/*                                     Data                                  */
+/*****************************************************************************/
+
+
+
+/* Screen instance data */
+typedef struct ScreenInstance ScreenInstance;
+struct ScreenInstance {
+
+    /* Settings passed from the simulator */
+    unsigned            Addr;           /* Address of the chip */
+    unsigned            Range;          /* Memory range */
+
+    /* X variables */
+    Display*            ScreenDisplay;
+    Window              ScreenWindow;
+    int                 Screen;
+    GC                  ScreenGC;
+
+    /* Windows rows and columns */
+    unsigned            Rows;
+    unsigned            Cols;
+
+    /* Window dimensions, 384*288 (PAL) */
+    unsigned            XTotal;
+    unsigned            YTotal;
+
+    /* Usable area within the window */
+    unsigned            XSize;
+    unsigned            YSize;
+
+    /* Offset of the usable area */
+    unsigned            XOffs;
+    unsigned            YOffs;
+
+    /* Character height */
+    unsigned            CharHeight;
+
+    /* Fore- and background color */
+    XColor              FgColor;
+    XColor              BgColor;
+
+    /* A list of 4 rectangles used to draw the border */
+    XRectangle          Border[4];
+
+    /* The virtual screen we are writing to. */
+    unsigned            MemSize;
+    unsigned char*      Mem;
+
+    /* The font data */
+    unsigned            FontDataSize;
+    unsigned char*      FontData;
+
+};
+
+/* If we have a video ram window, place it's instance data here */
+static ScreenInstance* VScreen = 0;
+
+
+
+/*****************************************************************************/
+/*                               Exported function                           */
+/*****************************************************************************/
+
+
+
+int GetChipData (const ChipData** Data, unsigned* Count)
+{
+    /* Pass the control structure to the caller */
+    *Data  = CData;
+    *Count = sizeof (CData) / sizeof (CData[0]);
+
+    /* Call was successful */
+    return 0;
+}
+
+
+
+/*****************************************************************************/
+/*                             Helper functions                              */
+/*****************************************************************************/
+
+
+
+static long CfgGetNum (void* CfgInfo, const char* AttrName, long Min, long Max, long Def)
+/* Read a number from the attributes. Check against Min/Max. Return the
+ * number or Def if it doesn't exist.
+ */
+{
+    long Val;
+
+    /* Read the attribute if it does exist */
+    if (Sim->GetCfgNum (CfgInfo, AttrName, &Val)) {
+        /* Check it */
+        if (Val < Min || Val > Max) {
+            Sim->Error ("Range error for attribute `%s'", AttrName);
+        }
+
+        /* Return it */
+        return Val;
+
+    } else {
+
+        /* Return the default */
+        return Def;
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                              Console screen                               */
+/*****************************************************************************/
+
+
+
+static int ScreenInitChip (const struct SimData* Data)
+/* Initialize the chip, return an error code */
+{
+    /* Remember the pointer */
+    Sim = Data;
+
+    /* Always successful */
+    return 0;
+}
+
+
+
+static void* ScreenCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo)
+/* Create a new chip instance */
+{
+    char*       Name;
+    FILE*       F;
+    unsigned    ColorDepth;
+    Colormap    CM;
+    XSizeHints  SizeHints;
+    XWMHints    WMHints;
+    Cursor      C;
+
+    /* Allocate the instance data */
+    ScreenInstance* V = VScreen = Sim->Malloc (sizeof (ScreenInstance));
+
+    /* Remember a few settings */
+    V->Addr  = Addr;
+    V->Range = Range;
+
+    /* Character height is 8 or given as attribute */
+    V->CharHeight = (unsigned) CfgGetNum (CfgInfo, "charheight", 8, 16, 8);
+
+    /* Allocate memory for the font */
+    V->FontDataSize = V->CharHeight * 256;
+    V->FontData = Sim->Malloc (V->FontDataSize);
+
+    /* We must have a "fontdata" attribute. Get it. */
+    if (Sim->GetCfgStr (CfgInfo, "fontdata", &Name) == 0) {
+        /* Attribute not found */
+        Sim->Error ("Attribute `fontdata' missing");        /* ### */
+    }
+
+    /* Open the file with the given name */
+    F = fopen (Name, "rb");
+    if (F == 0) {
+        Sim->Error ("Cannot open `%s': %s", Name, strerror (errno));
+    }
+
+    /* Read the file into the memory */
+    if (fread (V->FontData, 1, V->FontDataSize, F) != V->FontDataSize) {
+        Sim->Warning ("Font data file `%s' seems to be corrupt", Name);
+    }
+
+    /* Close the file */
+    fclose (F);
+
+    /* Free the file name */
+    Sim->Free (Name);
+
+    /* Read screen rows and columns */
+    V->Rows = (unsigned) CfgGetNum (CfgInfo, "rows", 15, 75, 25);
+    V->Cols = (unsigned) CfgGetNum (CfgInfo, "cols", 32, 132, 80);
+
+    /* Allocate screen memory and clear it */
+    V->MemSize = V->Rows * V->Cols;
+    V->Mem = Sim->Malloc (V->MemSize);
+    memset (V->Mem, ' ', V->MemSize);
+
+    /* Setup the window geometry */
+    V->XSize  = V->Cols * 8;
+    V->YSize  = V->Rows * V->CharHeight;
+    V->XTotal = V->XSize + 20;
+    V->YTotal = V->YSize + 20;
+    V->XOffs  = (V->XTotal - V->XSize) / 2;
+    V->YOffs  = (V->YTotal - V->YSize) / 2;
+
+    /* Setup the rectanges used to draw the exterior */
+    V->Border[0].x      = 0;
+    V->Border[0].y      = 0;
+    V->Border[0].width  = V->XTotal;
+    V->Border[0].height = V->YOffs;
+    V->Border[1].x      = 0;
+    V->Border[1].y      = V->YOffs + V->YSize;
+    V->Border[1].width  = V->XTotal;
+    V->Border[1].height = V->YOffs;
+    V->Border[2].x      = 0;
+    V->Border[2].y      = V->YOffs;
+    V->Border[2].width  = V->XOffs;
+    V->Border[2].height = V->YSize;
+    V->Border[3].x      = V->XOffs + V->XSize;
+    V->Border[3].y      = V->YOffs;
+    V->Border[3].width  = V->XOffs;
+    V->Border[3].height = V->YSize;
+
+    /* Open the X display. */
+    V->ScreenDisplay = XOpenDisplay ("");
+    if (V->ScreenDisplay == NULL) {
+        Sim->Error ("Screen: Cannot open X display");
+    }
+
+    /* Get a screen */
+    V->Screen = DefaultScreen (V->ScreenDisplay);
+
+    /* Check the available colors. For now, we expect direct colors, so we
+     * will check for a color depth of at least 16.
+     */
+    ColorDepth = XDefaultDepth (V->ScreenDisplay, V->Screen);
+    if (ColorDepth < 16) {
+        /* OOPS */
+        Sim->Error ("Screen: Need color display");
+    }
+
+    /* Get all needed colors */
+    V->FgColor = FgColor;
+    V->BgColor = BgColor;
+    CM = DefaultColormap (V->ScreenDisplay, V->Screen);
+    if (XAllocColor (V->ScreenDisplay, CM, &V->FgColor) == 0) {
+        Sim->Error ("Screen: Cannot allocate foreground color");
+    }
+    if (XAllocColor (V->ScreenDisplay, CM, &V->BgColor) == 0) {
+        Sim->Error ("Screen: Cannot allocate background color");
+    }
+
+    /* Set up the size hints structure */
+    SizeHints.x          = 0;
+    SizeHints.y          = 0;
+    SizeHints.flags      = PPosition | PSize | PMinSize | PMaxSize | PResizeInc;
+    SizeHints.width      = V->XTotal;
+    SizeHints.height     = V->YTotal;
+    SizeHints.min_width  = V->XTotal;
+    SizeHints.min_height = V->YTotal;
+    SizeHints.max_width  = V->XTotal;
+    SizeHints.max_height = V->YTotal;
+    SizeHints.width_inc  = 0;
+    SizeHints.height_inc = 0;
+    WMHints.flags        = InputHint;
+    WMHints.input        = True;
+
+    /* Create the window */
+    V->ScreenWindow = XCreateSimpleWindow (V->ScreenDisplay,
+                                           DefaultRootWindow (V->ScreenDisplay),
+                                           SizeHints.x,
+                                           SizeHints.y,
+                                           SizeHints.width,
+                                           SizeHints.height,
+                                           5,
+                                           V->FgColor.pixel,
+                                           V->BgColor.pixel);
+
+    /* Set the standard window properties */
+    XSetStandardProperties (V->ScreenDisplay,           /* Display */
+                            V->ScreenWindow,            /* Window */
+                            "sim65 console screen",     /* Window name */
+                            "sim65 console screen",     /* Icon name */
+                            None,                       /* Icon Pixmap */
+                            0,                          /* argv */
+                            0,                          /* argc */
+                            &SizeHints);                /* Hints */
+    XSetWMHints (V->ScreenDisplay, V->ScreenWindow, &WMHints);
+
+    /* GC creation and initialization */
+    V->ScreenGC = XCreateGC (V->ScreenDisplay, V->ScreenWindow, 0, 0);
+
+    /* Set the cursor to show over the console window */
+    C = XCreateFontCursor (V->ScreenDisplay, XC_pirate);
+    XDefineCursor (V->ScreenDisplay, V->ScreenWindow, C);
+
+    /* Select input events */
+    XSelectInput (V->ScreenDisplay, V->ScreenWindow, ExposureMask | StructureNotifyMask);
+
+    /* Show the window */
+    XMapRaised (V->ScreenDisplay, V->ScreenWindow);
+
+    /* Handle events */
+    ScreenEventLoop ();
+
+    /* Return the instance data */
+    return V;
+}
+
+
+
+static void ScreenDestroyInstance (void* Data)
+/* Destroy a chip instance */
+{
+    /* Cast the data pointer */
+    ScreenInstance* V = Data;
+
+    /* Free X resources */
+    XUndefineCursor (V->ScreenDisplay, V->ScreenWindow);
+    XFreeGC (V->ScreenDisplay, V->ScreenGC);
+    XDestroyWindow (V->ScreenDisplay, V->ScreenWindow);
+    XCloseDisplay (V->ScreenDisplay);
+
+    /* Clear the global pointer */
+    VScreen = 0;
+
+    /* Free the instance data */
+    Sim->Free (V->FontData);
+    Sim->Free (V->Mem);
+    Sim->Free (V);
+}
+
+
+
+static void ScreenWrite (void* Data, unsigned Offs, unsigned char Val)
+/* Write user data */
+{
+    /* Cast the data pointer */
+    ScreenInstance* V = Data;
+
+    /* Check the offset */
+    if (Offs >= V->MemSize) {
+        Sim->Break ("Screen: Accessing invalid memory at $%06X", V->Addr + Offs);
+        return;
+    }
+
+    /* Write the value */
+    V->Mem[Offs] = Val;
+
+    /* Schedule a redraw */
+    ScreenDrawChar (Offs);
+
+    /* Call the event loop */
+    ScreenEventLoop ();
+}
+
+
+
+static unsigned char ScreenRead (void* Data, unsigned Offs)
+/* Read user data */
+{
+    /* Cast the data pointer */
+    ScreenInstance* V = Data;
+
+    /* Check the offset */
+    if (Offs >= sizeof (V->Mem)) {
+        Sim->Break ("Screen: Accessing invalid memory at $%06X", V->Addr + Offs);
+        return 0xFF;
+    } else {
+        return V->Mem[Offs];
+    }
+}
+
+
+
+static void ScreenDrawBorder (void)
+/* Draw the complete border */
+{
+    if (VScreen) {
+        /* Set the border color */
+        XSetForeground (VScreen->ScreenDisplay, VScreen->ScreenGC, VScreen->BgColor.pixel);
+
+        /* Fill all rectangles that make the border */
+        XFillRectangles (VScreen->ScreenDisplay, VScreen->ScreenWindow, VScreen->ScreenGC,
+                         VScreen->Border, sizeof (VScreen->Border) / sizeof (VScreen->Border[0]));
+    }
+}
+
+
+
+static void ScreenDrawChar (unsigned Offs)
+/* Draw one character at the given position */
+{
+    unsigned    Row, Col;
+    XPoint      Points[128];
+    unsigned    PCount;
+
+    /* Get the character from the video RAM */
+    unsigned char C = VScreen->Mem[Offs];
+
+    /* Calculate the offset for the character data in the character ROM */
+    unsigned char* D = VScreen->FontData + (C * VScreen->CharHeight);
+
+    /* Calculate the coords for the output */
+    unsigned X = VScreen->XOffs + (Offs % VScreen->Cols) * 8;
+    unsigned Y = VScreen->YOffs + (Offs / VScreen->Cols) * VScreen->CharHeight;
+
+    /* Clear the character area with the background color */
+    XSetForeground (VScreen->ScreenDisplay, VScreen->ScreenGC, VScreen->BgColor.pixel);
+    XFillRectangle (VScreen->ScreenDisplay, VScreen->ScreenWindow, VScreen->ScreenGC, X, Y, 8, VScreen->CharHeight);
+
+    /* Prepare the foreground pixels */
+    PCount = 0;
+    for (Row = 0; Row < VScreen->CharHeight; ++Row) {
+
+        /* Get next byte from char rom */
+        unsigned Data = *D++;
+
+        /* Make pixels from this byte */
+        for (Col = 0; Col < 8; ++Col) {
+            if (Data & 0x80) {
+                /* Foreground pixel */
+                Points[PCount].x = X + Col;
+                Points[PCount].y = Y + Row;
+                ++PCount;
+            }
+            Data <<= 1;
+        }
+    }
+    if (PCount) {
+        /* Set the character color */
+        XSetForeground (VScreen->ScreenDisplay, VScreen->ScreenGC, VScreen->FgColor.pixel);
+
+        /* Draw the pixels */
+        XDrawPoints (VScreen->ScreenDisplay, VScreen->ScreenWindow, VScreen->ScreenGC,
+                     Points, PCount, CoordModeOrigin);
+    }
+}
+
+
+
+static void ScreenDrawArea (unsigned X1, unsigned Y1, unsigned X2, unsigned Y2)
+/* Update an area of the interior screen */
+{
+    unsigned X, Y;
+
+    /* Check if we have to draw anything */
+    if (X2 < VScreen->XOffs || Y2 < VScreen->YOffs ||
+        X1 >= VScreen->XOffs + VScreen->XSize ||
+        Y1 >= VScreen->YOffs + VScreen->YSize) {
+        /* Completely outside */
+        return;
+    }
+
+    /* Make the coordinates relative to the interior */
+    X1 -= VScreen->XOffs;
+    Y1 -= VScreen->YOffs;
+    X2 -= VScreen->XOffs;
+    Y2 -= VScreen->YOffs;
+
+    /* Loop updating characters */
+    for (Y = Y1; Y <= Y2; Y += 8) {
+        for (X = X1; X <= X2; X += 8) {
+            ScreenDrawChar ((Y / 8) * 40 + (X / 8));
+        }
+    }
+}
+
+
+
+static void ScreenDrawAllChars (void)
+/* Redraw the complete interior screen */
+{
+    unsigned I;
+    for (I = 0; I < 25*40; ++I) {
+        ScreenDrawChar (I);
+    }
+}
+
+
+
+static void ScreenEventLoop (void)
+/* Get all waiting events and handle them */
+{
+    unsigned X1, Y1, X2, Y2;
+
+    /* Read input events */
+    while (XEventsQueued (VScreen->ScreenDisplay, QueuedAfterFlush) != 0) {
+
+        /* Read an event */
+        XEvent Event;
+        XNextEvent (VScreen->ScreenDisplay, &Event);
+
+        switch (Event.type) {
+
+            case Expose:
+               /* Calculate the area to redraw, then update the screen */
+                X1 = Event.xexpose.x;
+                Y1 = Event.xexpose.y;
+                X2 = Event.xexpose.x + Event.xexpose.width - 1;
+                Y2 = Event.xexpose.y + Event.xexpose.height - 1;
+                if (X1 < VScreen->XOffs || X2 > VScreen->XOffs + VScreen->XSize ||
+                    Y1 < VScreen->YOffs || Y2 > VScreen->YOffs + VScreen->YSize) {
+                    /* Update the border */
+                    ScreenDrawBorder ();
+                }
+                ScreenDrawArea (X1, Y1, X2, Y2);
+                break;
+
+            case MappingNotify:
+                XRefreshKeyboardMapping (&Event.xmapping);
+                break;
+
+        }
+    }
+
+    /* Flush the outgoing event queue */
+    XFlush (VScreen->ScreenDisplay);
+}
+
+
+
index d0da776921cf99da781ae2285296aafcf45137fd..82a5e152ed876563523a0c0a3668199a52334032 100644 (file)
@@ -14,7 +14,8 @@ LDFLAGS       =
 
 #LIBS  = $(COMMON)/common.a
 
-CHIPS          =       ram.so          \
+CHIPS          =       console.so      \
+                ram.so         \
                rom.so          \
                stdio.so        \
                vic2.so