]> git.sur5r.net Git - cc65/blob - src/sim65/chips/vic2.c
Have 'avail' not be dependent on 'all'.
[cc65] / src / sim65 / chips / vic2.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  vic2.c                                   */
4 /*                                                                           */
5 /*                 VIC II plugin for the sim65 6502 simulator                */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2003      Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 #include <X11/Xlib.h>
42 #include <X11/Xutil.h>
43 #include <X11/Xatom.h>
44 #include <X11/cursorfont.h>
45
46 /* common */
47 #include "attrib.h"
48
49 /* sim65 */
50 #include "chipif.h"
51
52
53
54 /*****************************************************************************/
55 /*                                   Forwards                                */
56 /*****************************************************************************/
57
58
59
60 static int VicInitChip (const struct SimData* Data);
61 /* Initialize the chip, return an error code */
62
63 static void* VicCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo);
64 /* Create a new chip instance */
65
66 static void VicDestroyInstance (void* Data);
67 /* Destroy a chip instance */
68
69 static void VicWrite (void* Data, unsigned Offs, unsigned char Val);
70 /* Write user data */
71
72 static unsigned char VicRead (void* Data, unsigned Offs);
73 /* Read user data */
74
75 static int VRamInitChip (const struct SimData* Data);
76 /* Initialize the chip, return an error code */
77
78 static void* VRamCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo);
79 /* Create a new chip instance */
80
81 static void VRamDestroyInstance (void* Data);
82 /* Destroy a chip instance */
83
84 static void VRamWrite (void* Data, unsigned Offs, unsigned char Val);
85 /* Write user data */
86
87 static unsigned char VRamRead (void* Data, unsigned Offs);
88 /* Read user data */
89
90 static void VRamDrawBorder (void);
91 /* Draw the complete border */
92
93 static void VRamDrawChar (unsigned Offs);
94 /* Draw one character at the given position */
95
96 static void VRamDrawAllChars (void);
97 /* Redraw the complete interior screen */
98
99 static void VRamEventLoop (void);
100 /* Get all waiting events and handle them */
101
102 static int CRamInitChip (const struct SimData* Data);
103 /* Initialize the chip, return an error code */
104
105 static void* CRamCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo);
106 /* Create a new chip instance */
107
108 static void CRamDestroyInstance (void* Data);
109 /* Destroy a chip instance */
110
111 static void CRamWrite (void* Data, unsigned Offs, unsigned char Val);
112 /* Write user data */
113
114 static unsigned char CRamRead (void* Data, unsigned Offs);
115 /* Read user data */
116
117
118
119 /*****************************************************************************/
120 /*                                Global data                                */
121 /*****************************************************************************/
122
123
124
125 /* The SimData pointer we get when InitChip is called */
126 static const SimData* Sim;
127
128 /* Control data passed to the main program */
129 static const struct ChipData CData[] = {
130     {
131         "VIC2",                 /* Name of the chip */
132         CHIPDATA_TYPE_CHIP,     /* Type of the chip */
133         CHIPDATA_VER_MAJOR,     /* Version information */
134         CHIPDATA_VER_MINOR,
135
136         /* -- Exported functions -- */
137         VicInitChip,
138         VicCreateInstance,
139         VicDestroyInstance,
140         VicWrite,
141         VicWrite,
142         VicRead,
143         VicRead
144     },
145     {
146         "VIC2-VIDEORAM",        /* Name of the chip */
147         CHIPDATA_TYPE_CHIP,     /* Type of the chip */
148         CHIPDATA_VER_MAJOR,     /* Version information */
149         CHIPDATA_VER_MINOR,
150
151         /* -- Exported functions -- */
152         VRamInitChip,
153         VRamCreateInstance,
154         VRamDestroyInstance,
155         VRamWrite,
156         VRamWrite,
157         VRamRead,
158         VRamRead
159     },
160     {
161         "VIC2-COLORRAM",        /* Name of the chip */
162         CHIPDATA_TYPE_CHIP,     /* Type of the chip */
163         CHIPDATA_VER_MAJOR,     /* Version information */
164         CHIPDATA_VER_MINOR,
165
166         /* -- Exported functions -- */
167         CRamInitChip,
168         CRamCreateInstance,
169         CRamDestroyInstance,
170         CRamWrite,
171         CRamWrite,
172         CRamRead,
173         CRamRead
174     }
175 };
176
177 /* Defines for the VIC chip */
178 #define VIC_COLOR_COUNT         16
179 #define VIC_BLACK               0
180 #define VIC_WHITE               1
181
182 /* The application color map. VIC II color values are taken from
183  * http://www.pepto.de/projects/colorvic/ (Philip "Pepto" Timmermann)
184  */
185 static XColor VicColors [VIC_COLOR_COUNT] = {
186     { 0,   0*256,   0*256,   0*256, 0, 0 },     /* black */
187     { 0, 255*256, 255*256, 255*256, 0, 0 },     /* white */
188     { 0, 104*256,  55*256,  43*256, 0, 0 },     /* red */
189     { 0, 112*256, 163*256, 178*256, 0, 0 },     /* cyan */
190     { 0, 111*256,  61*256, 134*256, 0, 0 },     /* purple */
191     { 0,  88*256, 141*256,  67*256, 0, 0 },     /* green */
192     { 0,  53*256,  40*256, 121*256, 0, 0 },     /* blue */
193     { 0, 184*256, 199*256, 111*256, 0, 0 },     /* yellow */
194     { 0, 111*256,  79*256,  37*256, 0, 0 },     /* orange */
195     { 0,  67*256,  57*256,   0*256, 0, 0 },     /* brown */
196     { 0, 154*256, 103*256,  89*256, 0, 0 },     /* light red */
197     { 0,  68*256,  68*256,  68*256, 0, 0 },     /* dark grey */
198     { 0, 108*256, 108*256, 108*256, 0, 0 },     /* grey */
199     { 0, 154*256, 210*256, 132*256, 0, 0 },     /* light green */
200     { 0, 108*256,  94*256, 181*256, 0, 0 },     /* light blue */
201     { 0, 149*256, 149*256, 149*256, 0, 0 }      /* light grey */
202 };
203
204
205 /*****************************************************************************/
206 /*                                     Data                                  */
207 /*****************************************************************************/
208
209
210
211 /* VIC II instance data */
212 typedef struct VicInstance VicInstance;
213 struct VicInstance {
214     unsigned            Addr;           /* Address of the chip */
215     unsigned            Range;          /* Memory range */
216     unsigned char       Regs[47];       /* VIC registers */
217 };
218
219 /* Video RAM instance data */
220 typedef struct VRamInstance VRamInstance;
221 struct VRamInstance {
222
223     /* Settings passed from the simulator */
224     unsigned            Addr;           /* Address of the chip */
225     unsigned            Range;          /* Memory range */
226
227     /* X variables */
228     Display*    VicDisplay;
229     Window      VicWindow;
230     int         VicScreen;
231     GC          VicGC;
232
233     /* Window dimensions, 384*288 (PAL) */
234     unsigned XTotal;
235     unsigned YTotal;
236
237     /* Usable area within the window */
238     unsigned XSize;
239     unsigned YSize;
240
241     /* Offset of the usable area */
242     unsigned XOffs;
243     unsigned YOffs;
244
245     /* The window color map. */
246     XColor Colors [VIC_COLOR_COUNT];
247
248     /* A list of 4 rectangles used to draw the border */
249     XRectangle Border[4];
250
251     /* The virtual screen we are writing to. */
252     unsigned char Mem[0x400];
253
254     /* The character ROM data */
255     unsigned char CharRom[0x1000];
256
257 };
258
259 typedef struct CRamInstance CRamInstance;
260 struct CRamInstance {
261
262     /* Settings passed from the simulator */
263     unsigned            Addr;           /* Address of the chip */
264     unsigned            Range;          /* Memory range */
265
266     /* The memory we are writing to. */
267     unsigned char       Mem[0x400];
268 };
269
270 /* If we have a video ram window, place it's instance data here */
271 static VicInstance* Vic   = 0;
272 static VRamInstance* VRam = 0;
273 static CRamInstance* CRam = 0;
274
275
276
277 /*****************************************************************************/
278 /*                               Exported function                           */
279 /*****************************************************************************/
280
281
282
283 int GetChipData (const ChipData** Data, unsigned* Count)
284 {
285     /* Pass the control structure to the caller */
286     *Data  = CData;
287     *Count = sizeof (CData) / sizeof (CData[0]);
288
289     /* Call was successful */
290     return 0;
291 }
292
293
294
295 /*****************************************************************************/
296 /*                                VIC II Chip                                */
297 /*****************************************************************************/
298
299
300
301 static int VicInitChip (const struct SimData* Data)
302 /* Initialize the chip, return an error code */
303 {
304     /* Remember the pointer */
305     Sim = Data;
306
307     /* Always successful */
308     return 0;
309 }
310
311
312
313 static void* VicCreateInstance (unsigned Addr, unsigned Range,
314                                 void* CfgInfo attribute ((unused)))
315 /* Initialize a new chip instance */
316 {
317     /* Allocate a new instance structure */
318     VicInstance* V = Vic = Sim->Malloc (sizeof (VicInstance));
319
320     /* Initialize the structure, allocate RAM and attribute memory */
321     V->Addr  = Addr;
322     V->Range = Range;
323     memset (V->Regs, 0, sizeof (V->Regs));
324
325     /* Done, return the instance data */
326     return V;
327 }
328
329
330
331 static void VicDestroyInstance (void* Data)
332 /* Destroy a chip instance */
333 {
334     /* Cast the data pointer */
335     VicInstance* V = Data;
336
337     /* Free the instance data */
338     Sim->Free (V);
339 }
340
341
342
343 static void VicWrite (void* Data, unsigned Offs, unsigned char Val)
344 /* Write user data */
345 {
346     /* Cast the data pointer */
347     VicInstance* V = Data;
348
349     /* Check for a write outside our range */
350     if (Offs >= sizeof (V->Regs)) {
351         Sim->Break ("Writing to invalid VIC register at $%04X", V->Addr+Offs);
352     } else {
353
354         /* Do the write */
355         V->Regs[Offs] = Val;
356
357         /* Handle special registers */
358         switch (Offs) {
359             case 32:
360                 /* Exterior color */
361                 if (VRam) {
362                     VRamDrawBorder ();
363                 }
364                 break;
365             case 33:
366                 /* Background color #0 */
367                 if (VRam) {
368                     VRamDrawAllChars ();
369                 }
370                 break;
371
372         }
373
374         /* Handle the event queue */
375         if (VRam) {
376             VRamEventLoop ();
377         }
378     }
379 }
380
381
382
383 static unsigned char VicRead (void* Data, unsigned Offs)
384 /* Read user data */
385 {
386     /* Cast the data pointer */
387     VicInstance* V = Data;
388
389     /* Simulate the rasterline register */
390     if (V->Regs[17] & 0x80) {
391         if (++V->Regs[18] == (312 & 0xFF)) {
392             V->Regs[17] &= 0x7F;
393             V->Regs[18] = 0;
394         }
395     } else {
396         if (++V->Regs[18] == 0) {
397             V->Regs[17] |= 0x80;
398         }
399     }
400
401     /* Check for a read outside our range */
402     if (Offs >= sizeof (V->Regs)) {
403
404         Sim->Break ("Reading invalid VIC register at $%04X", V->Addr+Offs);
405         return 0xFF;
406
407     } else {
408
409         /* Do the read */
410         return V->Regs[Offs];
411
412     }
413 }
414
415
416
417 /*****************************************************************************/
418 /*                                 Video RAM                                 */
419 /*****************************************************************************/
420
421
422
423 static int VRamInitChip (const struct SimData* Data)
424 /* Initialize the chip, return an error code */
425 {
426     /* Remember the pointer */
427     Sim = Data;
428
429     /* Always successful */
430     return 0;
431 }
432
433
434
435 static void* VRamCreateInstance (unsigned Addr, unsigned Range, void* CfgInfo)
436 /* Create a new chip instance */
437 {
438     char*       Name;
439     FILE*       F;
440     unsigned    ColorDepth;
441     Colormap    CM;
442     unsigned    CIdx;
443     XSizeHints  SizeHints;
444     XWMHints    WMHints;
445     Cursor      C;
446
447     /* Allocate the instance data */
448     VRamInstance* V = VRam = Sim->Malloc (sizeof (VRamInstance));
449
450     /* Remember a few settings */
451     V->Addr  = Addr;
452     V->Range = Range;
453
454     /* Setup the window geometry */
455     V->XTotal = 384;    /* PAL */
456     V->YTotal = 288;
457     V->XSize  = 320;
458     V->YSize  = 200;
459     V->XOffs  = (V->XTotal - V->XSize) / 2;
460     V->YOffs  = (V->YTotal - V->YSize) / 2;
461
462     /* Setup the rectanges used to draw the exterior */
463     V->Border[0].x      = 0;
464     V->Border[0].y      = 0;
465     V->Border[0].width  = V->XTotal;
466     V->Border[0].height = V->YOffs;
467     V->Border[1].x      = 0;
468     V->Border[1].y      = V->YOffs + V->YSize;
469     V->Border[1].width  = V->XTotal;
470     V->Border[1].height = V->YOffs;
471     V->Border[2].x      = 0;
472     V->Border[2].y      = V->YOffs;
473     V->Border[2].width  = V->XOffs;
474     V->Border[2].height = V->YSize;
475     V->Border[3].x      = V->XOffs + V->XSize;
476     V->Border[3].y      = V->YOffs;
477     V->Border[3].width  = V->XOffs;
478     V->Border[3].height = V->YSize;
479
480     /* We must have a "file" attribute. Get it. */
481     if (Sim->GetCfgStr (CfgInfo, "file", &Name) == 0) {
482         /* Attribute not found */
483         Sim->Error ("Attribute `file' missing");        /* ### */
484     }
485
486     /* Open the file with the given name */
487     F = fopen (Name, "rb");
488     if (F == 0) {
489         Sim->Error ("Cannot open `%s': %s", Name, strerror (errno));
490     }
491
492     /* Read the file into the memory */
493     if (fread (V->CharRom, 1, sizeof (V->CharRom), F) != sizeof (V->CharRom)) {
494         Sim->Warning ("Char ROM `%s' seems to be corrupt", Name);
495     }
496
497     /* Close the file */
498     fclose (F);
499
500     /* Free the file name */
501     Sim->Free (Name);
502
503     /* Open the X display. */
504     V->VicDisplay = XOpenDisplay ("");
505     if (V->VicDisplay == NULL) {
506         Sim->Error ("VRAM: Cannot open X display");
507     }
508
509     /* Get a screen */
510     V->VicScreen = DefaultScreen (V->VicDisplay);
511
512     /* Check the available colors. For now, we expect direct colors, so we
513      * will check for a color depth of at least 16.
514      */
515     ColorDepth = XDefaultDepth (V->VicDisplay, V->VicScreen);
516     if (ColorDepth < 16) {
517         /* OOPS */
518         Sim->Error ("VRAM: Need color display");
519     }
520
521     /* Get all needed colors */
522     memcpy (V->Colors, VicColors, sizeof (V->Colors));
523     CM = DefaultColormap (V->VicDisplay, V->VicScreen);
524     for (CIdx = 0; CIdx < VIC_COLOR_COUNT; CIdx++) {
525         if (XAllocColor (V->VicDisplay, CM, &V->Colors [CIdx]) == 0) {
526             Sim->Error ("VRAM: Cannot allocate color");
527         }
528     }
529
530     /* Set up the size hints structure */
531     SizeHints.x          = 0;
532     SizeHints.y          = 0;
533     SizeHints.flags      = PPosition | PSize | PMinSize | PMaxSize | PResizeInc;
534     SizeHints.width      = V->XTotal;
535     SizeHints.height     = V->YTotal;
536     SizeHints.min_width  = V->XTotal;
537     SizeHints.min_height = V->YTotal;
538     SizeHints.max_width  = V->XTotal;
539     SizeHints.max_height = V->YTotal;
540     SizeHints.width_inc  = 0;
541     SizeHints.height_inc = 0;
542     WMHints.flags        = InputHint;
543     WMHints.input        = True;
544
545     /* Create the window */
546     V->VicWindow = XCreateSimpleWindow (V->VicDisplay,
547                                         DefaultRootWindow (V->VicDisplay),
548                                         SizeHints.x,
549                                         SizeHints.y,
550                                         SizeHints.width,
551                                         SizeHints.height,
552                                         5,
553                                         V->Colors [VIC_WHITE].pixel,
554                                         V->Colors [VIC_BLACK].pixel);
555
556     /* Set the standard window properties */
557     XSetStandardProperties (V->VicDisplay,              /* Display */
558                             V->VicWindow,               /* Window */
559                             "sim65 VIC screen",         /* Window name */
560                             "sim65 VIC screen",         /* Icon name */
561                             None,                       /* Icon Pixmap */
562                             0,                          /* argv */
563                             0,                          /* argc */
564                             &SizeHints);                /* Hints */
565     XSetWMHints (V->VicDisplay, V->VicWindow, &WMHints);
566
567     /* GC creation and initialization */
568     V->VicGC = XCreateGC (V->VicDisplay, V->VicWindow, 0, 0);
569
570     /* Set the cursor to show over the Vic window */
571     C = XCreateFontCursor (V->VicDisplay, XC_pirate);
572     XDefineCursor (V->VicDisplay, V->VicWindow, C);
573
574     /* Select input events */
575     XSelectInput (V->VicDisplay, V->VicWindow, ExposureMask | StructureNotifyMask);
576
577     /* Show the window */
578     XMapRaised (V->VicDisplay, V->VicWindow);
579
580     /* Handle events */
581     VRamEventLoop ();
582
583     /* Return the instance data */
584     return V;
585 }
586
587
588
589 static void VRamDestroyInstance (void* Data)
590 /* Destroy a chip instance */
591 {
592     /* Cast the data pointer */
593     VRamInstance* V = Data;
594
595     /* Free X resources */
596     XUndefineCursor (V->VicDisplay, V->VicWindow);
597     XFreeGC (V->VicDisplay, V->VicGC);
598     XDestroyWindow (V->VicDisplay, V->VicWindow);
599     XCloseDisplay (V->VicDisplay);
600
601     /* Clear the global pointer */
602     VRam = 0;
603
604     /* Free the instance data */
605     Sim->Free (V);
606 }
607
608
609
610 static void VRamWrite (void* Data, unsigned Offs, unsigned char Val)
611 /* Write user data */
612 {
613     /* Cast the data pointer */
614     VRamInstance* V = Data;
615
616     /* Check the offset */
617     if (Offs >= sizeof (V->Mem)) {
618         Sim->Break ("VRAM: Accessing invalid memory at $%06X", V->Addr + Offs);
619         return;
620     }
621
622     /* Write the value */
623     V->Mem[Offs] = Val;
624
625     /* If this changes the visible part of the screen, schedule a redraw */
626     if (Offs < 40*25) {
627
628         /* Schedule a redraw */
629         VRamDrawChar (Offs);
630
631         /* Call the event loop */
632         VRamEventLoop ();
633     }
634 }
635
636
637
638 static unsigned char VRamRead (void* Data, unsigned Offs)
639 /* Read user data */
640 {
641     /* Cast the data pointer */
642     VRamInstance* V = Data;
643
644     /* Check the offset */
645     if (Offs >= sizeof (V->Mem)) {
646         Sim->Break ("VRAM: Accessing invalid memory at $%06X", V->Addr + Offs);
647         return 0xFF;
648     } else {
649         return V->Mem[Offs];
650     }
651 }
652
653
654
655 static void VRamDrawBorder (void)
656 /* Draw the complete border */
657 {
658     if (Vic) {
659         /* Set the border color */
660         XSetForeground (VRam->VicDisplay, VRam->VicGC, VRam->Colors[Vic->Regs[32]].pixel);
661
662         /* Fill all rectangles that make the border */
663         XFillRectangles (VRam->VicDisplay, VRam->VicWindow, VRam->VicGC,
664                          VRam->Border, sizeof (VRam->Border) / sizeof (VRam->Border[0]));
665     }
666 }
667
668
669
670 static void VRamDrawChar (unsigned Offs)
671 /* Draw one character at the given position */
672 {
673     unsigned    Row, Col;
674     XPoint      Points[64];
675     unsigned    PCount;
676     unsigned    Color;
677
678     /* Get the character from the video RAM */
679     unsigned char C = VRam->Mem[Offs];
680
681     /* Calculate the offset for the character data in the character ROM */
682     unsigned char* D = VRam->CharRom + (C * 8);
683
684     /* Calculate the coords for the output */
685     unsigned X = VRam->XOffs + (Offs % 40) * 8;
686     unsigned Y = VRam->YOffs + (Offs / 40) * 8;
687
688     /* Clear the character area with the background color */
689     XSetForeground (VRam->VicDisplay, VRam->VicGC, VRam->Colors[Vic->Regs[33]].pixel);
690     XFillRectangle (VRam->VicDisplay, VRam->VicWindow, VRam->VicGC, X, Y, 8, 8);
691
692     /* Set the character color */
693     Color = CRam? CRam->Mem[Offs] & 0x0F : VIC_WHITE;
694     XSetForeground (VRam->VicDisplay, VRam->VicGC, VRam->Colors[Color].pixel);
695
696     /* Draw the foreground pixels */
697     PCount = 0;
698     for (Row = 0; Row < 8; ++Row) {
699
700         /* Get next byte from char rom */
701         unsigned Data = *D++;
702
703         /* Make pixels from this byte */
704         for (Col = 0; Col < 8; ++Col) {
705             if (Data & 0x80) {
706                 /* Foreground pixel */
707                 Points[PCount].x = X + Col;
708                 Points[PCount].y = Y + Row;
709                 ++PCount;
710             }
711             Data <<= 1;
712         }
713     }
714     if (PCount) {
715         XDrawPoints (VRam->VicDisplay, VRam->VicWindow, VRam->VicGC,
716                      Points, PCount, CoordModeOrigin);
717     }
718 }
719
720
721
722 static void VRamDrawArea (unsigned X1, unsigned Y1, unsigned X2, unsigned Y2)
723 /* Update an area of the interior screen */
724 {
725     unsigned X, Y;
726
727     /* Check if we have to draw anything */
728     if (X2 < VRam->XOffs || Y2 < VRam->YOffs ||
729         X1 >= VRam->XOffs + VRam->XSize ||
730         Y1 >= VRam->YOffs + VRam->YSize) {
731         /* Completely outside */
732         return;
733     }
734
735     /* Make the coordinates relative to the interior */
736     X1 -= VRam->XOffs;
737     Y1 -= VRam->YOffs;
738     X2 -= VRam->XOffs;
739     Y2 -= VRam->YOffs;
740
741     /* Loop updating characters */
742     for (Y = Y1; Y <= Y2; Y += 8) {
743         for (X = X1; X <= X2; X += 8) {
744             VRamDrawChar ((Y / 8) * 40 + (X / 8));
745         }
746     }
747 }
748
749
750
751 static void VRamDrawAllChars (void)
752 /* Redraw the complete interior screen */
753 {
754     unsigned I;
755     for (I = 0; I < 25*40; ++I) {
756         VRamDrawChar (I);
757     }
758 }
759
760
761
762 static void VRamEventLoop (void)
763 /* Get all waiting events and handle them */
764 {
765     unsigned X1, Y1, X2, Y2;
766
767     /* Read input events */
768     while (XEventsQueued (VRam->VicDisplay, QueuedAfterFlush) != 0) {
769
770         /* Read an event */
771         XEvent Event;
772         XNextEvent (VRam->VicDisplay, &Event);
773
774         switch (Event.type) {
775
776             case Expose:
777                 /* Calculate the area to redraw, then update the screen */
778                 X1 = Event.xexpose.x;
779                 Y1 = Event.xexpose.y;
780                 X2 = Event.xexpose.x + Event.xexpose.width - 1;
781                 Y2 = Event.xexpose.y + Event.xexpose.height - 1;
782                 if (X1 < VRam->XOffs || X2 > VRam->XOffs + VRam->XSize ||
783                     Y1 < VRam->YOffs || Y2 > VRam->YOffs + VRam->YSize) {
784                     /* Update the border */
785                     VRamDrawBorder ();
786                 }
787                 VRamDrawArea (X1, Y1, X2, Y2);
788                 break;
789
790             case MappingNotify:
791                 XRefreshKeyboardMapping (&Event.xmapping);
792                 break;
793
794         }
795     }
796
797     /* Flush the outgoing event queue */
798     XFlush (VRam->VicDisplay);
799 }
800
801
802
803 /*****************************************************************************/
804 /*                                 Color RAM                                 */
805 /*****************************************************************************/
806
807
808
809 static int CRamInitChip (const struct SimData* Data)
810 /* Initialize the chip, return an error code */
811 {
812     /* Remember the pointer */
813     Sim = Data;
814
815     /* Always successful */
816     return 0;
817 }
818
819
820
821 static void* CRamCreateInstance (unsigned Addr, unsigned Range,
822                                  void* CfgInfo attribute ((unused)))
823 /* Create a new chip instance */
824 {
825     /* Allocate the instance data */
826     CRamInstance* C = CRam = Sim->Malloc (sizeof (CRamInstance));
827
828     /* Remember a few settings */
829     C->Addr  = Addr;
830     C->Range = Range;
831
832     /* Clear the color RAM memory */
833     memset (C->Mem, 0x00, sizeof (C->Mem));
834
835     /* Return the instance data */
836     return C;
837 }
838
839
840
841 static void CRamDestroyInstance (void* Data)
842 /* Destroy a chip instance */
843 {
844     /* Clear the global pointer */
845     CRam = 0;
846
847     /* Free the instance data */
848     Sim->Free (Data);
849 }
850
851
852
853 static void CRamWrite (void* Data, unsigned Offs, unsigned char Val)
854 /* Write user data */
855 {
856     /* Cast the data pointer */
857     CRamInstance* C = Data;
858
859     /* Check the offset */
860     if (Offs >= sizeof (C->Mem)) {
861         Sim->Break ("CRAM: Accessing invalid memory at $%06X", C->Addr + Offs);
862         return;
863     }
864
865     /* Write the value */
866     C->Mem[Offs] = Val & 0x0F;
867
868     /* If this changes the visible part of the screen, schedule a redraw */
869     if (Offs < 40*25) {
870
871         /* Schedule a redraw */
872         VRamDrawChar (Offs);
873
874         /* Call the event loop */
875         VRamEventLoop ();
876     }
877 }
878
879
880
881 static unsigned char CRamRead (void* Data, unsigned Offs)
882 /* Read user data */
883 {
884     /* Cast the data pointer */
885     CRamInstance* C = Data;
886
887     /* Check the offset */
888     if (Offs >= sizeof (C->Mem)) {
889         Sim->Break ("CRAM: Accessing invalid memory at $%06X", C->Addr + Offs);
890         return 0xFF;
891     } else {
892         return C->Mem[Offs] | 0xF0;
893     }
894 }
895
896
897