1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-28 19:29:53 +00:00

Added a simulated console (memory mapped screen device, inpout device will

follow).


git-svn-id: svn://svn.cc65.org/cc65/trunk@4351 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-10-08 18:33:50 +00:00
parent 1122ddb05a
commit f2d1ea10d9
2 changed files with 639 additions and 1 deletions

637
src/sim65/chips/console.c Normal file
View File

@ -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);
}

View File

@ -14,7 +14,8 @@ LDFLAGS =
#LIBS = $(COMMON)/common.a
CHIPS = ram.so \
CHIPS = console.so \
ram.so \
rom.so \
stdio.so \
vic2.so