ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC.cpp
Revision: 1.4
Committed: 2005-06-27T19:55:48Z (18 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.3: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * VIC.cpp - 6569R5 emulation (line based)
3     *
4 cebix 1.4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * Notes:
23     * ------
24     *
25     * - The EmulateLine() function is called for every emulated
26     * raster line. It computes one pixel row of the graphics
27     * according to the current VIC register settings and returns
28     * the number of cycles available for the CPU in that line.
29     * - The graphics are output into an 8 bit chunky bitmap
30     * - The sprite-graphics priority handling and collision
31     * detection is done in a bit-oriented way with masks.
32     * The foreground/background pixel mask for the graphics
33     * is stored in the fore_mask_buf[] array. Multicolor
34     * sprites are converted from their original chunky format
35     * to a bitplane representation (two bit masks) for easier
36     * handling of priorities and collisions.
37     * - The sprite-sprite priority handling and collision
38     * detection is done in with the byte array spr_coll_buf[],
39     * that is used to keep track of which sprites are already
40     * visible at certain X positions.
41     *
42     * Incompatibilities:
43     * ------------------
44     *
45     * - Raster effects that are achieved by modifying VIC registers
46     * in the middle of a raster line cannot be emulated
47     * - Sprite collisions are only detected within the visible
48     * screen area (excluding borders)
49     * - Sprites are only drawn if they completely fit within the
50     * left/right limits of the chunky bitmap
51     * - The Char ROM is not visible in the bitmap displays at
52     * addresses $0000 and $8000
53     * - The IRQ is cleared on every write access to the flag
54     * register. This is a hack for the RMW instructions of the
55     * 6510 that first write back the original value.
56     */
57    
58     #include "sysdeps.h"
59    
60     #include "VIC.h"
61     #include "C64.h"
62     #include "CPUC64.h"
63     #include "Display.h"
64     #include "Prefs.h"
65    
66    
67     // Test alignment on run-time for processors that can't access unaligned:
68     #ifdef __riscos__
69     #define ALIGNMENT_CHECK
70     #endif
71    
72     // First and last displayed line
73     const unsigned FIRST_DISP_LINE = 0x10;
74     const unsigned LAST_DISP_LINE = 0x11f;
75    
76     // First and last possible line for Bad Lines
77     const unsigned FIRST_DMA_LINE = 0x30;
78     const unsigned LAST_DMA_LINE = 0xf7;
79    
80     // Display window coordinates
81     const int ROW25_YSTART = 0x33;
82     const int ROW25_YSTOP = 0xfb;
83     const int ROW24_YSTART = 0x37;
84     const int ROW24_YSTOP = 0xf7;
85    
86     #if defined(SMALL_DISPLAY)
87     /* This does not work yet, the sprite code doesn't know about it. */
88     const int COL40_XSTART = 0x14;
89     const int COL40_XSTOP = 0x154;
90     const int COL38_XSTART = 0x1B;
91     const int COL38_XSTOP = 0x14B;
92     #else
93     const int COL40_XSTART = 0x20;
94     const int COL40_XSTOP = 0x160;
95     const int COL38_XSTART = 0x27;
96     const int COL38_XSTOP = 0x157;
97     #endif
98    
99    
100     // Tables for sprite X expansion
101     uint16 ExpTable[256] = {
102     0x0000, 0x0003, 0x000C, 0x000F, 0x0030, 0x0033, 0x003C, 0x003F,
103     0x00C0, 0x00C3, 0x00CC, 0x00CF, 0x00F0, 0x00F3, 0x00FC, 0x00FF,
104     0x0300, 0x0303, 0x030C, 0x030F, 0x0330, 0x0333, 0x033C, 0x033F,
105     0x03C0, 0x03C3, 0x03CC, 0x03CF, 0x03F0, 0x03F3, 0x03FC, 0x03FF,
106     0x0C00, 0x0C03, 0x0C0C, 0x0C0F, 0x0C30, 0x0C33, 0x0C3C, 0x0C3F,
107     0x0CC0, 0x0CC3, 0x0CCC, 0x0CCF, 0x0CF0, 0x0CF3, 0x0CFC, 0x0CFF,
108     0x0F00, 0x0F03, 0x0F0C, 0x0F0F, 0x0F30, 0x0F33, 0x0F3C, 0x0F3F,
109     0x0FC0, 0x0FC3, 0x0FCC, 0x0FCF, 0x0FF0, 0x0FF3, 0x0FFC, 0x0FFF,
110     0x3000, 0x3003, 0x300C, 0x300F, 0x3030, 0x3033, 0x303C, 0x303F,
111     0x30C0, 0x30C3, 0x30CC, 0x30CF, 0x30F0, 0x30F3, 0x30FC, 0x30FF,
112     0x3300, 0x3303, 0x330C, 0x330F, 0x3330, 0x3333, 0x333C, 0x333F,
113     0x33C0, 0x33C3, 0x33CC, 0x33CF, 0x33F0, 0x33F3, 0x33FC, 0x33FF,
114     0x3C00, 0x3C03, 0x3C0C, 0x3C0F, 0x3C30, 0x3C33, 0x3C3C, 0x3C3F,
115     0x3CC0, 0x3CC3, 0x3CCC, 0x3CCF, 0x3CF0, 0x3CF3, 0x3CFC, 0x3CFF,
116     0x3F00, 0x3F03, 0x3F0C, 0x3F0F, 0x3F30, 0x3F33, 0x3F3C, 0x3F3F,
117     0x3FC0, 0x3FC3, 0x3FCC, 0x3FCF, 0x3FF0, 0x3FF3, 0x3FFC, 0x3FFF,
118     0xC000, 0xC003, 0xC00C, 0xC00F, 0xC030, 0xC033, 0xC03C, 0xC03F,
119     0xC0C0, 0xC0C3, 0xC0CC, 0xC0CF, 0xC0F0, 0xC0F3, 0xC0FC, 0xC0FF,
120     0xC300, 0xC303, 0xC30C, 0xC30F, 0xC330, 0xC333, 0xC33C, 0xC33F,
121     0xC3C0, 0xC3C3, 0xC3CC, 0xC3CF, 0xC3F0, 0xC3F3, 0xC3FC, 0xC3FF,
122     0xCC00, 0xCC03, 0xCC0C, 0xCC0F, 0xCC30, 0xCC33, 0xCC3C, 0xCC3F,
123     0xCCC0, 0xCCC3, 0xCCCC, 0xCCCF, 0xCCF0, 0xCCF3, 0xCCFC, 0xCCFF,
124     0xCF00, 0xCF03, 0xCF0C, 0xCF0F, 0xCF30, 0xCF33, 0xCF3C, 0xCF3F,
125     0xCFC0, 0xCFC3, 0xCFCC, 0xCFCF, 0xCFF0, 0xCFF3, 0xCFFC, 0xCFFF,
126     0xF000, 0xF003, 0xF00C, 0xF00F, 0xF030, 0xF033, 0xF03C, 0xF03F,
127     0xF0C0, 0xF0C3, 0xF0CC, 0xF0CF, 0xF0F0, 0xF0F3, 0xF0FC, 0xF0FF,
128     0xF300, 0xF303, 0xF30C, 0xF30F, 0xF330, 0xF333, 0xF33C, 0xF33F,
129     0xF3C0, 0xF3C3, 0xF3CC, 0xF3CF, 0xF3F0, 0xF3F3, 0xF3FC, 0xF3FF,
130     0xFC00, 0xFC03, 0xFC0C, 0xFC0F, 0xFC30, 0xFC33, 0xFC3C, 0xFC3F,
131     0xFCC0, 0xFCC3, 0xFCCC, 0xFCCF, 0xFCF0, 0xFCF3, 0xFCFC, 0xFCFF,
132     0xFF00, 0xFF03, 0xFF0C, 0xFF0F, 0xFF30, 0xFF33, 0xFF3C, 0xFF3F,
133     0xFFC0, 0xFFC3, 0xFFCC, 0xFFCF, 0xFFF0, 0xFFF3, 0xFFFC, 0xFFFF
134     };
135    
136     uint16 MultiExpTable[256] = {
137     0x0000, 0x0005, 0x000A, 0x000F, 0x0050, 0x0055, 0x005A, 0x005F,
138     0x00A0, 0x00A5, 0x00AA, 0x00AF, 0x00F0, 0x00F5, 0x00FA, 0x00FF,
139     0x0500, 0x0505, 0x050A, 0x050F, 0x0550, 0x0555, 0x055A, 0x055F,
140     0x05A0, 0x05A5, 0x05AA, 0x05AF, 0x05F0, 0x05F5, 0x05FA, 0x05FF,
141     0x0A00, 0x0A05, 0x0A0A, 0x0A0F, 0x0A50, 0x0A55, 0x0A5A, 0x0A5F,
142     0x0AA0, 0x0AA5, 0x0AAA, 0x0AAF, 0x0AF0, 0x0AF5, 0x0AFA, 0x0AFF,
143     0x0F00, 0x0F05, 0x0F0A, 0x0F0F, 0x0F50, 0x0F55, 0x0F5A, 0x0F5F,
144     0x0FA0, 0x0FA5, 0x0FAA, 0x0FAF, 0x0FF0, 0x0FF5, 0x0FFA, 0x0FFF,
145     0x5000, 0x5005, 0x500A, 0x500F, 0x5050, 0x5055, 0x505A, 0x505F,
146     0x50A0, 0x50A5, 0x50AA, 0x50AF, 0x50F0, 0x50F5, 0x50FA, 0x50FF,
147     0x5500, 0x5505, 0x550A, 0x550F, 0x5550, 0x5555, 0x555A, 0x555F,
148     0x55A0, 0x55A5, 0x55AA, 0x55AF, 0x55F0, 0x55F5, 0x55FA, 0x55FF,
149     0x5A00, 0x5A05, 0x5A0A, 0x5A0F, 0x5A50, 0x5A55, 0x5A5A, 0x5A5F,
150     0x5AA0, 0x5AA5, 0x5AAA, 0x5AAF, 0x5AF0, 0x5AF5, 0x5AFA, 0x5AFF,
151     0x5F00, 0x5F05, 0x5F0A, 0x5F0F, 0x5F50, 0x5F55, 0x5F5A, 0x5F5F,
152     0x5FA0, 0x5FA5, 0x5FAA, 0x5FAF, 0x5FF0, 0x5FF5, 0x5FFA, 0x5FFF,
153     0xA000, 0xA005, 0xA00A, 0xA00F, 0xA050, 0xA055, 0xA05A, 0xA05F,
154     0xA0A0, 0xA0A5, 0xA0AA, 0xA0AF, 0xA0F0, 0xA0F5, 0xA0FA, 0xA0FF,
155     0xA500, 0xA505, 0xA50A, 0xA50F, 0xA550, 0xA555, 0xA55A, 0xA55F,
156     0xA5A0, 0xA5A5, 0xA5AA, 0xA5AF, 0xA5F0, 0xA5F5, 0xA5FA, 0xA5FF,
157     0xAA00, 0xAA05, 0xAA0A, 0xAA0F, 0xAA50, 0xAA55, 0xAA5A, 0xAA5F,
158     0xAAA0, 0xAAA5, 0xAAAA, 0xAAAF, 0xAAF0, 0xAAF5, 0xAAFA, 0xAAFF,
159     0xAF00, 0xAF05, 0xAF0A, 0xAF0F, 0xAF50, 0xAF55, 0xAF5A, 0xAF5F,
160     0xAFA0, 0xAFA5, 0xAFAA, 0xAFAF, 0xAFF0, 0xAFF5, 0xAFFA, 0xAFFF,
161     0xF000, 0xF005, 0xF00A, 0xF00F, 0xF050, 0xF055, 0xF05A, 0xF05F,
162     0xF0A0, 0xF0A5, 0xF0AA, 0xF0AF, 0xF0F0, 0xF0F5, 0xF0FA, 0xF0FF,
163     0xF500, 0xF505, 0xF50A, 0xF50F, 0xF550, 0xF555, 0xF55A, 0xF55F,
164     0xF5A0, 0xF5A5, 0xF5AA, 0xF5AF, 0xF5F0, 0xF5F5, 0xF5FA, 0xF5FF,
165     0xFA00, 0xFA05, 0xFA0A, 0xFA0F, 0xFA50, 0xFA55, 0xFA5A, 0xFA5F,
166     0xFAA0, 0xFAA5, 0xFAAA, 0xFAAF, 0xFAF0, 0xFAF5, 0xFAFA, 0xFAFF,
167     0xFF00, 0xFF05, 0xFF0A, 0xFF0F, 0xFF50, 0xFF55, 0xFF5A, 0xFF5F,
168     0xFFA0, 0xFFA5, 0xFFAA, 0xFFAF, 0xFFF0, 0xFFF5, 0xFFFA, 0xFFFF
169     };
170    
171     #ifdef __POWERPC__
172     static union {
173     struct {
174     uint8 a,b,c,d,e,f,g,h;
175     } a;
176     double b;
177     } TextColorTable[16][16][256];
178     #else
179     static union {
180     struct {
181     uint8 a,b,c,d;
182     } a;
183     uint32 b;
184     } TextColorTable[16][16][256][2];
185     #endif
186    
187     #ifdef GLOBAL_VARS
188     static uint16 mc_color_lookup[4];
189     #ifndef CAN_ACCESS_UNALIGNED
190     static uint8 text_chunky_buf[40*8];
191     #endif
192     static uint16 mx[8]; // VIC registers
193     static uint8 mx8;
194     static uint8 my[8];
195     static uint8 ctrl1, ctrl2;
196     static uint8 lpx, lpy;
197     static uint8 me, mxe, mye, mdp, mmc;
198     static uint8 vbase;
199     static uint8 irq_flag, irq_mask;
200     static uint8 clx_spr, clx_bgr;
201     static uint8 ec, b0c, b1c, b2c, b3c, mm0, mm1;
202     static uint8 sc[8];
203    
204     static uint8 *ram, *char_rom, *color_ram; // Pointers to RAM and ROM
205     static C64 *the_c64; // Pointer to C64
206     static C64Display *the_display; // Pointer to C64Display
207     static MOS6510 *the_cpu; // Pointer to 6510
208    
209     static uint8 colors[256]; // Indices of the 16 C64 colors (16 times mirrored to avoid "& 0x0f")
210    
211     static uint8 ec_color, b0c_color, b1c_color, b2c_color, b3c_color; // Indices for exterior/background colors
212     static uint8 mm0_color, mm1_color; // Indices for MOB multicolors
213     static uint8 spr_color[8]; // Indices for MOB colors
214    
215     static uint32 ec_color_long; // ec_color expanded to 32 bits
216    
217     static uint8 matrix_line[40]; // Buffer for video line, read in Bad Lines
218     static uint8 color_line[40]; // Buffer for color line, read in Bad Lines
219    
220     #ifdef __POWERPC__
221     static double chunky_tmp[DISPLAY_X/8]; // Temporary line buffer for GameKit speedup
222     #endif
223     static uint8 *chunky_line_start; // Pointer to start of current line in bitmap buffer
224     static int xmod; // Number of bytes per row
225    
226     static uint8 *matrix_base; // Video matrix base
227     static uint8 *char_base; // Character generator base
228     static uint8 *bitmap_base; // Bitmap base
229    
230     static uint16 raster_y; // Current raster line
231     static uint16 irq_raster; // Interrupt raster line
232     static uint16 dy_start; // Comparison values for border logic
233     static uint16 dy_stop;
234     static uint16 rc; // Row counter
235     static uint16 vc; // Video counter
236     static uint16 vc_base; // Video counter base
237     static uint16 x_scroll; // X scroll value
238     static uint16 y_scroll; // Y scroll value
239     static uint16 cia_vabase; // CIA VA14/15 video base
240    
241     static int display_idx; // Index of current display mode
242     static int skip_counter; // Counter for frame-skipping
243    
244     static uint16 mc[8]; // Sprite data counters
245     static uint8 sprite_on; // 8 Flags: Sprite display/DMA active
246    
247     static uint8 spr_coll_buf[0x180]; // Buffer for sprite-sprite collisions and priorities
248     static uint8 fore_mask_buf[0x180/8]; // Foreground mask for sprite-graphics collisions and priorities
249    
250     static bool display_state; // true: Display state, false: Idle state
251     static bool border_on; // Flag: Upper/lower border on
252     static bool border_40_col; // Flag: 40 column border
253     static bool frame_skipped; // Flag: Frame is being skipped
254     static uint8 bad_lines_enabled; // Flag: Bad Lines enabled for this frame
255     static bool lp_triggered; // Flag: Lightpen was triggered in this frame
256     #endif
257    
258    
259     /*
260     * Constructor: Initialize variables
261     */
262    
263     static void init_text_color_table(uint8 *colors)
264     {
265     for (int i = 0; i < 16; i++)
266     for (int j = 0; j < 16; j++)
267     for (int k = 0; k < 256; k++) {
268     #ifdef __POWERPC__
269     TextColorTable[i][j][k].a.a = colors[k & 128 ? i : j];
270     TextColorTable[i][j][k].a.b = colors[k & 64 ? i : j];
271     TextColorTable[i][j][k].a.c = colors[k & 32 ? i : j];
272     TextColorTable[i][j][k].a.d = colors[k & 16 ? i : j];
273     TextColorTable[i][j][k].a.e = colors[k & 8 ? i : j];
274     TextColorTable[i][j][k].a.f = colors[k & 4 ? i : j];
275     TextColorTable[i][j][k].a.g = colors[k & 2 ? i : j];
276     TextColorTable[i][j][k].a.h = colors[k & 1 ? i : j];
277     #else
278     TextColorTable[i][j][k][0].a.a = colors[k & 128 ? i : j];
279     TextColorTable[i][j][k][0].a.b = colors[k & 64 ? i : j];
280     TextColorTable[i][j][k][0].a.c = colors[k & 32 ? i : j];
281     TextColorTable[i][j][k][0].a.d = colors[k & 16 ? i : j];
282     TextColorTable[i][j][k][1].a.a = colors[k & 8 ? i : j];
283     TextColorTable[i][j][k][1].a.b = colors[k & 4 ? i : j];
284     TextColorTable[i][j][k][1].a.c = colors[k & 2 ? i : j];
285     TextColorTable[i][j][k][1].a.d = colors[k & 1 ? i : j];
286     #endif
287     }
288     }
289    
290     MOS6569::MOS6569(C64 *c64, C64Display *disp, MOS6510 *CPU, uint8 *RAM, uint8 *Char, uint8 *Color)
291     #ifndef GLOBAL_VARS
292     : ram(RAM), char_rom(Char), color_ram(Color), the_c64(c64), the_display(disp), the_cpu(CPU)
293     #endif
294     {
295     int i;
296    
297     // Set pointers
298     #ifdef GLOBAL_VARS
299     the_c64 = c64;
300     the_display = disp;
301     the_cpu = CPU;
302     ram = RAM;
303     char_rom = Char;
304     color_ram = Color;
305     #endif
306     matrix_base = RAM;
307     char_base = RAM;
308     bitmap_base = RAM;
309    
310     // Get bitmap info
311     chunky_line_start = disp->BitmapBase();
312     xmod = disp->BitmapXMod();
313    
314     // Initialize VIC registers
315     mx8 = 0;
316     ctrl1 = ctrl2 = 0;
317     lpx = lpy = 0;
318     me = mxe = mye = mdp = mmc = 0;
319     vbase = irq_flag = irq_mask = 0;
320     clx_spr = clx_bgr = 0;
321     cia_vabase = 0;
322     ec = b0c = b1c = b2c = b3c = mm0 = mm1 = 0;
323     for (i=0; i<8; i++) mx[i] = my[i] = sc[i] = 0;
324    
325     // Initialize other variables
326     raster_y = 0xffff;
327     rc = 7;
328     irq_raster = vc = vc_base = x_scroll = y_scroll = 0;
329     dy_start = ROW24_YSTART;
330     dy_stop = ROW24_YSTOP;
331    
332     display_idx = 0;
333     display_state = false;
334     border_on = false;
335     lp_triggered = false;
336    
337     sprite_on = 0;
338     for (i=0; i<8; i++)
339     mc[i] = 63;
340    
341     frame_skipped = false;
342     skip_counter = 1;
343    
344     // Clear foreground mask
345     memset(fore_mask_buf, 0, DISPLAY_X/8);
346    
347     // Preset colors to black
348     disp->InitColors(colors);
349     init_text_color_table(colors);
350     ec_color = b0c_color = b1c_color = b2c_color = b3c_color = mm0_color = mm1_color = colors[0];
351     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
352     for (i=0; i<8; i++) spr_color[i] = colors[0];
353     }
354    
355    
356     /*
357     * Reinitialize the colors table for when the palette has changed
358     */
359    
360     void MOS6569::ReInitColors(void)
361     {
362     int i;
363    
364     // Build inverse color table.
365     uint8 xlate_colors[256];
366     memset(xlate_colors, 0, sizeof(xlate_colors));
367     for (i = 0; i < 16; i++)
368     xlate_colors[colors[i]] = i;
369    
370     // Get the new colors.
371     the_display->InitColors(colors);
372     init_text_color_table(colors);
373    
374     // Build color translation table.
375     for (i = 0; i < 256; i++)
376     xlate_colors[i] = colors[xlate_colors[i]];
377    
378     // Translate all the old colors variables.
379     ec_color = colors[ec];
380     ec_color_long = ec_color | (ec_color << 8) | (ec_color << 16) | (ec_color << 24);
381     b0c_color = colors[b0c];
382     b1c_color = colors[b1c];
383     b2c_color = colors[b2c];
384     b3c_color = colors[b3c];
385     mm0_color = colors[mm0];
386     mm1_color = colors[mm1];
387     for (i = 0; i < 8; i++)
388     spr_color[i] = colors[sc[i]];
389     mc_color_lookup[0] = b0c_color | (b0c_color << 8);
390     mc_color_lookup[1] = b1c_color | (b1c_color << 8);
391     mc_color_lookup[2] = b2c_color | (b2c_color << 8);
392    
393     // Translate the chunky buffer.
394     uint8 *scanline = the_display->BitmapBase();
395     for (int y = 0; y < DISPLAY_Y; y++) {
396     for (int x = 0; x < DISPLAY_X; x++)
397     scanline[x] = xlate_colors[scanline[x]];
398     scanline += xmod;
399     }
400     }
401    
402     #ifdef GLOBAL_VARS
403     static void make_mc_table(void)
404     #else
405     void MOS6569::make_mc_table(void)
406     #endif
407     {
408     mc_color_lookup[0] = b0c_color | (b0c_color << 8);
409     mc_color_lookup[1] = b1c_color | (b1c_color << 8);
410     mc_color_lookup[2] = b2c_color | (b2c_color << 8);
411     }
412    
413    
414     /*
415     * Convert video address to pointer
416     */
417    
418     #ifdef GLOBAL_VARS
419     static inline uint8 *get_physical(uint16 adr)
420     #else
421     inline uint8 *MOS6569::get_physical(uint16 adr)
422     #endif
423     {
424     int va = adr | cia_vabase;
425     if ((va & 0x7000) == 0x1000)
426     return char_rom + (va & 0x0fff);
427     else
428     return ram + va;
429     }
430    
431    
432     /*
433     * Get VIC state
434     */
435    
436     void MOS6569::GetState(MOS6569State *vd)
437     {
438     int i;
439    
440     vd->m0x = mx[0] & 0xff; vd->m0y = my[0];
441     vd->m1x = mx[1] & 0xff; vd->m1y = my[1];
442     vd->m2x = mx[2] & 0xff; vd->m2y = my[2];
443     vd->m3x = mx[3] & 0xff; vd->m3y = my[3];
444     vd->m4x = mx[4] & 0xff; vd->m4y = my[4];
445     vd->m5x = mx[5] & 0xff; vd->m5y = my[5];
446     vd->m6x = mx[6] & 0xff; vd->m6y = my[6];
447     vd->m7x = mx[7] & 0xff; vd->m7y = my[7];
448     vd->mx8 = mx8;
449    
450     vd->ctrl1 = (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
451     vd->raster = raster_y & 0xff;
452     vd->lpx = lpx; vd->lpy = lpy;
453     vd->ctrl2 = ctrl2;
454     vd->vbase = vbase;
455     vd->irq_flag = irq_flag;
456     vd->irq_mask = irq_mask;
457    
458     vd->me = me; vd->mxe = mxe; vd->mye = mye; vd->mdp = mdp; vd->mmc = mmc;
459     vd->mm = clx_spr; vd->md = clx_bgr;
460    
461     vd->ec = ec;
462     vd->b0c = b0c; vd->b1c = b1c; vd->b2c = b2c; vd->b3c = b3c;
463     vd->mm0 = mm0; vd->mm1 = mm1;
464     vd->m0c = sc[0]; vd->m1c = sc[1];
465     vd->m2c = sc[2]; vd->m3c = sc[3];
466     vd->m4c = sc[4]; vd->m5c = sc[5];
467     vd->m6c = sc[6]; vd->m7c = sc[7];
468    
469     vd->pad0 = 0;
470     vd->irq_raster = irq_raster;
471     vd->vc = vc;
472     vd->vc_base = vc_base;
473     vd->rc = rc;
474     vd->spr_dma = vd->spr_disp = sprite_on;
475     for (i=0; i<8; i++)
476     vd->mc[i] = vd->mc_base[i] = mc[i];
477     vd->display_state = display_state;
478     vd->bad_line = raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled;
479     vd->bad_line_enable = bad_lines_enabled;
480     vd->lp_triggered = lp_triggered;
481     vd->border_on = border_on;
482    
483     vd->bank_base = cia_vabase;
484     vd->matrix_base = ((vbase & 0xf0) << 6) | cia_vabase;
485     vd->char_base = ((vbase & 0x0e) << 10) | cia_vabase;
486     vd->bitmap_base = ((vbase & 0x08) << 10) | cia_vabase;
487     for (i=0; i<8; i++)
488     vd->sprite_base[i] = (matrix_base[0x3f8 + i] << 6) | cia_vabase;
489    
490     vd->cycle = 1;
491     vd->raster_x = 0;
492     vd->ml_index = 0;
493     vd->ref_cnt = 0xff;
494     vd->last_vic_byte = 0;
495     vd->ud_border_on = border_on;
496     }
497    
498    
499     /*
500     * Set VIC state (only works if in VBlank)
501     */
502    
503     void MOS6569::SetState(MOS6569State *vd)
504     {
505     int i, j;
506    
507     mx[0] = vd->m0x; my[0] = vd->m0y;
508     mx[1] = vd->m1x; my[1] = vd->m1y;
509     mx[2] = vd->m2x; my[2] = vd->m2y;
510     mx[3] = vd->m3x; my[3] = vd->m3y;
511     mx[4] = vd->m4x; my[4] = vd->m4y;
512     mx[5] = vd->m5x; my[5] = vd->m5y;
513     mx[6] = vd->m6x; my[6] = vd->m6y;
514     mx[7] = vd->m7x; my[7] = vd->m7y;
515     mx8 = vd->mx8;
516     for (i=0, j=1; i<8; i++, j<<=1) {
517     if (mx8 & j)
518     mx[i] |= 0x100;
519     else
520     mx[i] &= 0xff;
521     }
522    
523     ctrl1 = vd->ctrl1;
524     ctrl2 = vd->ctrl2;
525     x_scroll = ctrl2 & 7;
526     y_scroll = ctrl1 & 7;
527     if (ctrl1 & 8) {
528     dy_start = ROW25_YSTART;
529     dy_stop = ROW25_YSTOP;
530     } else {
531     dy_start = ROW24_YSTART;
532     dy_stop = ROW24_YSTOP;
533     }
534     border_40_col = ctrl2 & 8;
535     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
536    
537     raster_y = 0;
538     lpx = vd->lpx; lpy = vd->lpy;
539    
540     vbase = vd->vbase;
541     cia_vabase = vd->bank_base;
542     matrix_base = get_physical((vbase & 0xf0) << 6);
543     char_base = get_physical((vbase & 0x0e) << 10);
544     bitmap_base = get_physical((vbase & 0x08) << 10);
545    
546     irq_flag = vd->irq_flag;
547     irq_mask = vd->irq_mask;
548    
549     me = vd->me; mxe = vd->mxe; mye = vd->mye; mdp = vd->mdp; mmc = vd->mmc;
550     clx_spr = vd->mm; clx_bgr = vd->md;
551    
552     ec = vd->ec;
553     ec_color = colors[ec];
554     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
555    
556     b0c = vd->b0c; b1c = vd->b1c; b2c = vd->b2c; b3c = vd->b3c;
557     b0c_color = colors[b0c];
558     b1c_color = colors[b1c];
559     b2c_color = colors[b2c];
560     b3c_color = colors[b3c];
561     make_mc_table();
562    
563     mm0 = vd->mm0; mm1 = vd->mm1;
564     mm0_color = colors[mm0];
565     mm1_color = colors[mm1];
566    
567     sc[0] = vd->m0c; sc[1] = vd->m1c;
568     sc[2] = vd->m2c; sc[3] = vd->m3c;
569     sc[4] = vd->m4c; sc[5] = vd->m5c;
570     sc[6] = vd->m6c; sc[7] = vd->m7c;
571     for (i=0; i<8; i++)
572     spr_color[i] = colors[sc[i]];
573    
574     irq_raster = vd->irq_raster;
575     vc = vd->vc;
576     vc_base = vd->vc_base;
577     rc = vd->rc;
578     sprite_on = vd->spr_dma;
579     for (i=0; i<8; i++)
580     mc[i] = vd->mc[i];
581     display_state = vd->display_state;
582     bad_lines_enabled = vd->bad_line_enable;
583     lp_triggered = vd->lp_triggered;
584     border_on = vd->border_on;
585     }
586    
587    
588     /*
589     * Trigger raster IRQ
590     */
591    
592     #ifdef GLOBAL_VARS
593     static inline void raster_irq(void)
594     #else
595     inline void MOS6569::raster_irq(void)
596     #endif
597     {
598     irq_flag |= 0x01;
599     if (irq_mask & 0x01) {
600     irq_flag |= 0x80;
601     the_cpu->TriggerVICIRQ();
602     }
603     }
604    
605    
606     /*
607     * Read from VIC register
608     */
609    
610     uint8 MOS6569::ReadRegister(uint16 adr)
611     {
612     switch (adr) {
613     case 0x00: case 0x02: case 0x04: case 0x06:
614     case 0x08: case 0x0a: case 0x0c: case 0x0e:
615     return mx[adr >> 1];
616    
617     case 0x01: case 0x03: case 0x05: case 0x07:
618     case 0x09: case 0x0b: case 0x0d: case 0x0f:
619     return my[adr >> 1];
620    
621     case 0x10: // Sprite X position MSB
622     return mx8;
623    
624     case 0x11: // Control register 1
625     return (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
626    
627     case 0x12: // Raster counter
628     return raster_y;
629    
630     case 0x13: // Light pen X
631     return lpx;
632    
633     case 0x14: // Light pen Y
634     return lpy;
635    
636     case 0x15: // Sprite enable
637     return me;
638    
639     case 0x16: // Control register 2
640     return ctrl2 | 0xc0;
641    
642     case 0x17: // Sprite Y expansion
643     return mye;
644    
645     case 0x18: // Memory pointers
646     return vbase | 0x01;
647    
648     case 0x19: // IRQ flags
649     return irq_flag | 0x70;
650    
651     case 0x1a: // IRQ mask
652     return irq_mask | 0xf0;
653    
654     case 0x1b: // Sprite data priority
655     return mdp;
656    
657     case 0x1c: // Sprite multicolor
658     return mmc;
659    
660     case 0x1d: // Sprite X expansion
661     return mxe;
662    
663     case 0x1e:{ // Sprite-sprite collision
664     uint8 ret = clx_spr;
665     clx_spr = 0; // Read and clear
666     return ret;
667     }
668    
669     case 0x1f:{ // Sprite-background collision
670     uint8 ret = clx_bgr;
671     clx_bgr = 0; // Read and clear
672     return ret;
673     }
674    
675     case 0x20: return ec | 0xf0;
676     case 0x21: return b0c | 0xf0;
677     case 0x22: return b1c | 0xf0;
678     case 0x23: return b2c | 0xf0;
679     case 0x24: return b3c | 0xf0;
680     case 0x25: return mm0 | 0xf0;
681     case 0x26: return mm1 | 0xf0;
682    
683     case 0x27: case 0x28: case 0x29: case 0x2a:
684     case 0x2b: case 0x2c: case 0x2d: case 0x2e:
685     return sc[adr - 0x27] | 0xf0;
686    
687     default:
688     return 0xff;
689     }
690     }
691    
692    
693     /*
694     * Write to VIC register
695     */
696    
697     void MOS6569::WriteRegister(uint16 adr, uint8 byte)
698     {
699     switch (adr) {
700     case 0x00: case 0x02: case 0x04: case 0x06:
701     case 0x08: case 0x0a: case 0x0c: case 0x0e:
702     mx[adr >> 1] = (mx[adr >> 1] & 0xff00) | byte;
703     break;
704    
705     case 0x10:{
706     int i, j;
707     mx8 = byte;
708     for (i=0, j=1; i<8; i++, j<<=1) {
709     if (mx8 & j)
710     mx[i] |= 0x100;
711     else
712     mx[i] &= 0xff;
713     }
714     break;
715     }
716    
717     case 0x01: case 0x03: case 0x05: case 0x07:
718     case 0x09: case 0x0b: case 0x0d: case 0x0f:
719     my[adr >> 1] = byte;
720     break;
721    
722     case 0x11:{ // Control register 1
723     ctrl1 = byte;
724     y_scroll = byte & 7;
725    
726     uint16 new_irq_raster = (irq_raster & 0xff) | ((byte & 0x80) << 1);
727     if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
728     raster_irq();
729     irq_raster = new_irq_raster;
730    
731     if (byte & 8) {
732     dy_start = ROW25_YSTART;
733     dy_stop = ROW25_YSTOP;
734     } else {
735     dy_start = ROW24_YSTART;
736     dy_stop = ROW24_YSTOP;
737     }
738    
739     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
740     break;
741     }
742    
743     case 0x12:{ // Raster counter
744     uint16 new_irq_raster = (irq_raster & 0xff00) | byte;
745     if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
746     raster_irq();
747     irq_raster = new_irq_raster;
748     break;
749     }
750    
751     case 0x15: // Sprite enable
752     me = byte;
753     break;
754    
755     case 0x16: // Control register 2
756     ctrl2 = byte;
757     x_scroll = byte & 7;
758     border_40_col = byte & 8;
759     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
760     break;
761    
762     case 0x17: // Sprite Y expansion
763     mye = byte;
764     break;
765    
766     case 0x18: // Memory pointers
767     vbase = byte;
768     matrix_base = get_physical((byte & 0xf0) << 6);
769     char_base = get_physical((byte & 0x0e) << 10);
770     bitmap_base = get_physical((byte & 0x08) << 10);
771     break;
772    
773     case 0x19: // IRQ flags
774     irq_flag = irq_flag & (~byte & 0x0f);
775     the_cpu->ClearVICIRQ(); // Clear interrupt (hack!)
776     if (irq_flag & irq_mask) // Set master bit if allowed interrupt still pending
777     irq_flag |= 0x80;
778     break;
779    
780     case 0x1a: // IRQ mask
781     irq_mask = byte & 0x0f;
782     if (irq_flag & irq_mask) { // Trigger interrupt if pending and now allowed
783     irq_flag |= 0x80;
784     the_cpu->TriggerVICIRQ();
785     } else {
786     irq_flag &= 0x7f;
787     the_cpu->ClearVICIRQ();
788     }
789     break;
790    
791     case 0x1b: // Sprite data priority
792     mdp = byte;
793     break;
794    
795     case 0x1c: // Sprite multicolor
796     mmc = byte;
797     break;
798    
799     case 0x1d: // Sprite X expansion
800     mxe = byte;
801     break;
802    
803     case 0x20:
804     ec_color = colors[ec = byte];
805     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
806     break;
807    
808     case 0x21:
809     if (b0c != byte) {
810     b0c_color = colors[b0c = byte & 0xF];
811     make_mc_table();
812     }
813     break;
814    
815     case 0x22:
816     if (b1c != byte) {
817     b1c_color = colors[b1c = byte & 0xF];
818     make_mc_table();
819     }
820     break;
821    
822     case 0x23:
823     if (b2c != byte) {
824     b2c_color = colors[b2c = byte & 0xF];
825     make_mc_table();
826     }
827     break;
828    
829     case 0x24: b3c_color = colors[b3c = byte & 0xF]; break;
830     case 0x25: mm0_color = colors[mm0 = byte]; break;
831     case 0x26: mm1_color = colors[mm1 = byte]; break;
832    
833     case 0x27: case 0x28: case 0x29: case 0x2a:
834     case 0x2b: case 0x2c: case 0x2d: case 0x2e:
835     spr_color[adr - 0x27] = colors[sc[adr - 0x27] = byte];
836     break;
837     }
838     }
839    
840    
841     /*
842     * CIA VA14/15 has changed
843     */
844    
845     void MOS6569::ChangedVA(uint16 new_va)
846     {
847     cia_vabase = new_va << 14;
848     WriteRegister(0x18, vbase); // Force update of memory pointers
849     }
850    
851    
852     /*
853     * Trigger lightpen interrupt, latch lightpen coordinates
854     */
855    
856     void MOS6569::TriggerLightpen(void)
857     {
858     if (!lp_triggered) { // Lightpen triggers only once per frame
859     lp_triggered = true;
860    
861     lpx = 0; // Latch current coordinates
862     lpy = raster_y;
863    
864     irq_flag |= 0x08; // Trigger IRQ
865     if (irq_mask & 0x08) {
866     irq_flag |= 0x80;
867     the_cpu->TriggerVICIRQ();
868     }
869     }
870     }
871    
872    
873     /*
874     * VIC vertical blank: Reset counters and redraw screen
875     */
876    
877     #ifdef GLOBAL_VARS
878     static inline void vblank(void)
879     #else
880     inline void MOS6569::vblank(void)
881     #endif
882     {
883     raster_y = vc_base = 0;
884     lp_triggered = false;
885    
886     if (!(frame_skipped = --skip_counter))
887     skip_counter = ThePrefs.SkipFrames;
888    
889     the_c64->VBlank(!frame_skipped);
890    
891     // Get bitmap pointer for next frame. This must be done
892     // after calling the_c64->VBlank() because the preferences
893     // and screen configuration may have been changed there
894     chunky_line_start = the_display->BitmapBase();
895     xmod = the_display->BitmapXMod();
896     }
897    
898    
899     #ifdef __riscos__
900     #include "el_Acorn.h"
901     #else
902    
903     #ifdef GLOBAL_VARS
904     static inline void el_std_text(uint8 *p, uint8 *q, uint8 *r)
905     #else
906     inline void MOS6569::el_std_text(uint8 *p, uint8 *q, uint8 *r)
907     #endif
908     {
909     unsigned int b0cc = b0c;
910     #ifdef __POWERPC__
911     double *dp = (double *)p - 1;
912     #else
913     uint32 *lp = (uint32 *)p;
914     #endif
915     uint8 *cp = color_line;
916     uint8 *mp = matrix_line;
917    
918     // Loop for 40 characters
919     for (int i=0; i<40; i++) {
920     uint8 color = cp[i];
921     uint8 data = r[i] = q[mp[i] << 3];
922    
923     #ifdef __POWERPC__
924     *++dp = TextColorTable[color][b0cc][data].b;
925     #else
926     *lp++ = TextColorTable[color][b0cc][data][0].b;
927     *lp++ = TextColorTable[color][b0cc][data][1].b;
928     #endif
929     }
930     }
931    
932    
933     #ifdef GLOBAL_VARS
934     static inline void el_mc_text(uint8 *p, uint8 *q, uint8 *r)
935     #else
936     inline void MOS6569::el_mc_text(uint8 *p, uint8 *q, uint8 *r)
937     #endif
938     {
939     uint16 *wp = (uint16 *)p;
940     uint8 *cp = color_line;
941     uint8 *mp = matrix_line;
942     uint16 *mclp = mc_color_lookup;
943    
944     // Loop for 40 characters
945     for (int i=0; i<40; i++) {
946     uint8 data = q[mp[i] << 3];
947    
948     if (cp[i] & 8) {
949     uint8 color = colors[cp[i] & 7];
950     r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
951     mclp[3] = color | (color << 8);
952     *wp++ = mclp[(data >> 6) & 3];
953     *wp++ = mclp[(data >> 4) & 3];
954     *wp++ = mclp[(data >> 2) & 3];
955     *wp++ = mclp[(data >> 0) & 3];
956    
957     } else { // Standard mode in multicolor mode
958     uint8 color = cp[i];
959     r[i] = data;
960     #ifdef __POWERPC__
961     *(double *)wp = TextColorTable[color][b0c][data].b;
962     wp += 4;
963     #else
964     *(uint32 *)wp = TextColorTable[color][b0c][data][0].b;
965     wp += 2;
966     *(uint32 *)wp = TextColorTable[color][b0c][data][1].b;
967     wp += 2;
968     #endif
969     }
970     }
971     }
972    
973    
974     #ifdef GLOBAL_VARS
975     static inline void el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
976     #else
977     inline void MOS6569::el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
978     #endif
979     {
980     #ifdef __POWERPC__
981     double *dp = (double *)p-1;
982     #else
983     uint32 *lp = (uint32 *)p;
984     #endif
985     uint8 *mp = matrix_line;
986    
987     // Loop for 40 characters
988     for (int i=0; i<40; i++, q+=8) {
989     uint8 data = r[i] = *q;
990     uint8 color = mp[i] >> 4;
991     uint8 bcolor = mp[i] & 15;
992    
993     #ifdef __POWERPC__
994     *++dp = TextColorTable[color][bcolor][data].b;
995     #else
996     *lp++ = TextColorTable[color][bcolor][data][0].b;
997     *lp++ = TextColorTable[color][bcolor][data][1].b;
998     #endif
999     }
1000     }
1001    
1002    
1003     #ifdef GLOBAL_VARS
1004     static inline void el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
1005     #else
1006     inline void MOS6569::el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
1007     #endif
1008     {
1009     uint16 lookup[4];
1010     uint16 *wp = (uint16 *)p - 1;
1011     uint8 *cp = color_line;
1012     uint8 *mp = matrix_line;
1013    
1014     #ifdef __GNU_C__
1015     &lookup; /* Statement with no effect other than preventing GCC from
1016     * putting the array in a register, which generates
1017     * spectacularly bad code. */
1018     #endif
1019    
1020     lookup[0] = (b0c_color << 8) | b0c_color;
1021    
1022     // Loop for 40 characters
1023     for (int i=0; i<40; i++, q+=8) {
1024     uint8 color, acolor, bcolor;
1025    
1026     color = colors[mp[i] >> 4];
1027     lookup[1] = (color << 8) | color;
1028     bcolor = colors[mp[i]];
1029     lookup[2] = (bcolor << 8) | bcolor;
1030     acolor = colors[cp[i]];
1031     lookup[3] = (acolor << 8) | acolor;
1032    
1033     uint8 data = *q;
1034     r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
1035    
1036     *++wp = lookup[(data >> 6) & 3];
1037     *++wp = lookup[(data >> 4) & 3];
1038     *++wp = lookup[(data >> 2) & 3];
1039     *++wp = lookup[(data >> 0) & 3];
1040     }
1041     }
1042    
1043    
1044     #ifdef GLOBAL_VARS
1045     static inline void el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1046     #else
1047     inline void MOS6569::el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1048     #endif
1049     {
1050     #ifdef __POWERPC__
1051     double *dp = (double *)p - 1;
1052     #else
1053     uint32 *lp = (uint32 *)p;
1054     #endif
1055     uint8 *cp = color_line;
1056     uint8 *mp = matrix_line;
1057     uint8 *bcp = &b0c;
1058    
1059     // Loop for 40 characters
1060     for (int i=0; i<40; i++) {
1061     uint8 data = r[i] = mp[i];
1062     uint8 color = cp[i];
1063     uint8 bcolor = bcp[(data >> 6) & 3];
1064    
1065     data = q[(data & 0x3f) << 3];
1066     #ifdef __POWERPC__
1067     *++dp = TextColorTable[color][bcolor][data].b;
1068     #else
1069     *lp++ = TextColorTable[color][bcolor][data][0].b;
1070     *lp++ = TextColorTable[color][bcolor][data][1].b;
1071     #endif
1072     }
1073     }
1074    
1075    
1076     #ifdef GLOBAL_VARS
1077     static inline void el_std_idle(uint8 *p, uint8 *r)
1078     #else
1079     inline void MOS6569::el_std_idle(uint8 *p, uint8 *r)
1080     #endif
1081     {
1082     #ifdef __POWERPC__
1083     uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1084     double *dp = (double *)p - 1;
1085     double conv = TextColorTable[0][b0c][data].b;
1086     r--;
1087    
1088     for (int i=0; i<40; i++) {
1089     *++dp = conv;
1090     *++r = data;
1091     }
1092     #else
1093     uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1094     uint32 *lp = (uint32 *)p;
1095     uint32 conv0 = TextColorTable[0][b0c][data][0].b;
1096     uint32 conv1 = TextColorTable[0][b0c][data][1].b;
1097    
1098     for (int i=0; i<40; i++) {
1099     *lp++ = conv0;
1100     *lp++ = conv1;
1101     *r++ = data;
1102     }
1103     #endif
1104     }
1105    
1106    
1107     #ifdef GLOBAL_VARS
1108     static inline void el_mc_idle(uint8 *p, uint8 *r)
1109     #else
1110     inline void MOS6569::el_mc_idle(uint8 *p, uint8 *r)
1111     #endif
1112     {
1113     uint8 data = *get_physical(0x3fff);
1114     uint32 *lp = (uint32 *)p - 1;
1115     r--;
1116    
1117     uint16 lookup[4];
1118     lookup[0] = (b0c_color << 8) | b0c_color;
1119     lookup[1] = lookup[2] = lookup[3] = colors[0];
1120    
1121     uint16 conv0 = (lookup[(data >> 6) & 3] << 16) | lookup[(data >> 4) & 3];
1122     uint16 conv1 = (lookup[(data >> 2) & 3] << 16) | lookup[(data >> 0) & 3];
1123    
1124     for (int i=0; i<40; i++) {
1125     *++lp = conv0;
1126     *++lp = conv1;
1127     *++r = data;
1128     }
1129     }
1130    
1131     #endif //__riscos__
1132    
1133    
1134     #ifdef GLOBAL_VARS
1135     static inline void el_sprites(uint8 *chunky_ptr)
1136     #else
1137     inline void MOS6569::el_sprites(uint8 *chunky_ptr)
1138     #endif
1139     {
1140     int i;
1141     int snum, sbit; // Sprite number/bit mask
1142     int spr_coll=0, gfx_coll=0;
1143    
1144     // Draw each active sprite
1145     for (snum=0, sbit=1; snum<8; snum++, sbit<<=1)
1146     if ((sprite_on & sbit) && mx[snum] < DISPLAY_X-32) {
1147     int spr_mask_pos; // Sprite bit position in fore_mask_buf
1148     uint32 sdata, fore_mask;
1149    
1150     uint8 *p = chunky_ptr + mx[snum] + 8;
1151     uint8 *q = spr_coll_buf + mx[snum] + 8;
1152    
1153     uint8 *sdatap = get_physical(matrix_base[0x3f8 + snum] << 6 | mc[snum]);
1154     sdata = (*sdatap << 24) | (*(sdatap+1) << 16) | (*(sdatap+2) << 8);
1155    
1156     uint8 color = spr_color[snum];
1157    
1158     spr_mask_pos = mx[snum] + 8 - x_scroll;
1159    
1160     uint8 *fmbp = fore_mask_buf + (spr_mask_pos / 8);
1161     int sshift = spr_mask_pos & 7;
1162     fore_mask = (((*(fmbp+0) << 24) | (*(fmbp+1) << 16) | (*(fmbp+2) << 8)
1163     | (*(fmbp+3))) << sshift) | (*(fmbp+4) >> (8-sshift));
1164    
1165     if (mxe & sbit) { // X-expanded
1166     if (mx[snum] >= DISPLAY_X-56)
1167     continue;
1168    
1169     uint32 sdata_l = 0, sdata_r = 0, fore_mask_r;
1170     fore_mask_r = (((*(fmbp+4) << 24) | (*(fmbp+5) << 16) | (*(fmbp+6) << 8)
1171     | (*(fmbp+7))) << sshift) | (*(fmbp+8) >> (8-sshift));
1172    
1173     if (mmc & sbit) { // Multicolor mode
1174     uint32 plane0_l, plane0_r, plane1_l, plane1_r;
1175    
1176     // Expand sprite data
1177     sdata_l = MultiExpTable[sdata >> 24 & 0xff] << 16 | MultiExpTable[sdata >> 16 & 0xff];
1178     sdata_r = MultiExpTable[sdata >> 8 & 0xff] << 16;
1179    
1180     // Convert sprite chunky pixels to bitplanes
1181     plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
1182     plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
1183     plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
1184     plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
1185    
1186     // Collision with graphics?
1187     if ((fore_mask & (plane0_l | plane1_l)) || (fore_mask_r & (plane0_r | plane1_r))) {
1188     gfx_coll |= sbit;
1189     if (mdp & sbit) {
1190     plane0_l &= ~fore_mask; // Mask sprite if in background
1191     plane1_l &= ~fore_mask;
1192     plane0_r &= ~fore_mask_r;
1193     plane1_r &= ~fore_mask_r;
1194     }
1195     }
1196    
1197     // Paint sprite
1198     for (i=0; i<32; i++, plane0_l<<=1, plane1_l<<=1) {
1199     uint8 col;
1200     if (plane1_l & 0x80000000) {
1201     if (plane0_l & 0x80000000)
1202     col = mm1_color;
1203     else
1204     col = color;
1205     } else {
1206     if (plane0_l & 0x80000000)
1207     col = mm0_color;
1208     else
1209     continue;
1210     }
1211     if (q[i])
1212     spr_coll |= q[i] | sbit;
1213     else {
1214     p[i] = col;
1215     q[i] = sbit;
1216     }
1217     }
1218     for (; i<48; i++, plane0_r<<=1, plane1_r<<=1) {
1219     uint8 col;
1220     if (plane1_r & 0x80000000) {
1221     if (plane0_r & 0x80000000)
1222     col = mm1_color;
1223     else
1224     col = color;
1225     } else {
1226     if (plane0_r & 0x80000000)
1227     col = mm0_color;
1228     else
1229     continue;
1230     }
1231     if (q[i])
1232     spr_coll |= q[i] | sbit;
1233     else {
1234     p[i] = col;
1235     q[i] = sbit;
1236     }
1237     }
1238    
1239     } else { // Standard mode
1240    
1241     // Expand sprite data
1242     sdata_l = ExpTable[sdata >> 24 & 0xff] << 16 | ExpTable[sdata >> 16 & 0xff];
1243     sdata_r = ExpTable[sdata >> 8 & 0xff] << 16;
1244    
1245     // Collision with graphics?
1246     if ((fore_mask & sdata_l) || (fore_mask_r & sdata_r)) {
1247     gfx_coll |= sbit;
1248     if (mdp & sbit) {
1249     sdata_l &= ~fore_mask; // Mask sprite if in background
1250     sdata_r &= ~fore_mask_r;
1251     }
1252     }
1253    
1254     // Paint sprite
1255     for (i=0; i<32; i++, sdata_l<<=1)
1256     if (sdata_l & 0x80000000) {
1257     if (q[i]) // Collision with sprite?
1258     spr_coll |= q[i] | sbit;
1259     else { // Draw pixel if no collision
1260     p[i] = color;
1261     q[i] = sbit;
1262     }
1263     }
1264     for (; i<48; i++, sdata_r<<=1)
1265     if (sdata_r & 0x80000000) {
1266     if (q[i]) // Collision with sprite?
1267     spr_coll |= q[i] | sbit;
1268     else { // Draw pixel if no collision
1269     p[i] = color;
1270     q[i] = sbit;
1271     }
1272     }
1273     }
1274    
1275     } else // Unexpanded
1276    
1277     if (mmc & sbit) { // Multicolor mode
1278     uint32 plane0, plane1;
1279    
1280     // Convert sprite chunky pixels to bitplanes
1281     plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
1282     plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
1283    
1284     // Collision with graphics?
1285     if (fore_mask & (plane0 | plane1)) {
1286     gfx_coll |= sbit;
1287     if (mdp & sbit) {
1288     plane0 &= ~fore_mask; // Mask sprite if in background
1289     plane1 &= ~fore_mask;
1290     }
1291     }
1292    
1293     // Paint sprite
1294     for (i=0; i<24; i++, plane0<<=1, plane1<<=1) {
1295     uint8 col;
1296     if (plane1 & 0x80000000) {
1297     if (plane0 & 0x80000000)
1298     col = mm1_color;
1299     else
1300     col = color;
1301     } else {
1302     if (plane0 & 0x80000000)
1303     col = mm0_color;
1304     else
1305     continue;
1306     }
1307     if (q[i])
1308     spr_coll |= q[i] | sbit;
1309     else {
1310     p[i] = col;
1311     q[i] = sbit;
1312     }
1313     }
1314    
1315     } else { // Standard mode
1316    
1317     // Collision with graphics?
1318     if (fore_mask & sdata) {
1319     gfx_coll |= sbit;
1320     if (mdp & sbit)
1321     sdata &= ~fore_mask; // Mask sprite if in background
1322     }
1323    
1324     // Paint sprite
1325     for (i=0; i<24; i++, sdata<<=1)
1326     if (sdata & 0x80000000) {
1327     if (q[i]) { // Collision with sprite?
1328     spr_coll |= q[i] | sbit;
1329     } else { // Draw pixel if no collision
1330     p[i] = color;
1331     q[i] = sbit;
1332     }
1333     }
1334    
1335     }
1336     }
1337    
1338     if (ThePrefs.SpriteCollisions) {
1339    
1340     // Check sprite-sprite collisions
1341     if (clx_spr)
1342     clx_spr |= spr_coll;
1343     else {
1344     clx_spr |= spr_coll;
1345     irq_flag |= 0x04;
1346     if (irq_mask & 0x04) {
1347     irq_flag |= 0x80;
1348     the_cpu->TriggerVICIRQ();
1349     }
1350     }
1351    
1352     // Check sprite-background collisions
1353     if (clx_bgr)
1354     clx_bgr |= gfx_coll;
1355     else {
1356     clx_bgr |= gfx_coll;
1357     irq_flag |= 0x02;
1358     if (irq_mask & 0x02) {
1359     irq_flag |= 0x80;
1360     the_cpu->TriggerVICIRQ();
1361     }
1362     }
1363     }
1364     }
1365    
1366    
1367     #ifdef GLOBAL_VARS
1368     static inline int el_update_mc(int raster)
1369     #else
1370     inline int MOS6569::el_update_mc(int raster)
1371     #endif
1372     {
1373     int i, j;
1374     int cycles_used = 0;
1375     uint8 spron = sprite_on;
1376     uint8 spren = me;
1377     uint8 sprye = mye;
1378     uint8 raster8bit = raster;
1379     uint16 *mcp = mc;
1380     uint8 *myp = my;
1381    
1382     // Increment sprite data counters
1383     for (i=0, j=1; i<8; i++, j<<=1, mcp++, myp++) {
1384    
1385     // Sprite enabled?
1386     if (spren & j)
1387    
1388     // Yes, activate if Y position matches raster counter
1389     if (*myp == (raster8bit & 0xff)) {
1390     *mcp = 0;
1391     spron |= j;
1392     } else
1393     goto spr_off;
1394     else
1395     spr_off:
1396     // No, turn sprite off when data counter exceeds 60
1397     // and increment counter
1398     if (*mcp != 63) {
1399     if (sprye & j) { // Y expansion
1400     if (!((*myp ^ raster8bit) & 1)) {
1401     *mcp += 3;
1402     cycles_used += 2;
1403     if (*mcp == 63)
1404     spron &= ~j;
1405     }
1406     } else {
1407     *mcp += 3;
1408     cycles_used += 2;
1409     if (*mcp == 63)
1410     spron &= ~j;
1411     }
1412     }
1413     }
1414    
1415     sprite_on = spron;
1416     return cycles_used;
1417     }
1418    
1419    
1420     #ifdef __POWERPC__
1421     static asm void fastcopy(register uchar *dst, register uchar *src);
1422     static asm void fastcopy(register uchar *dst, register uchar *src)
1423     {
1424     lfd fp0,0(src)
1425     lfd fp1,8(src)
1426     lfd fp2,16(src)
1427     lfd fp3,24(src)
1428     lfd fp4,32(src)
1429     lfd fp5,40(src)
1430     lfd fp6,48(src)
1431     lfd fp7,56(src)
1432     addi src,src,64
1433     stfd fp0,0(dst)
1434     stfd fp1,8(dst)
1435     stfd fp2,16(dst)
1436     stfd fp3,24(dst)
1437     stfd fp4,32(dst)
1438     stfd fp5,40(dst)
1439     stfd fp6,48(dst)
1440     stfd fp7,56(dst)
1441     addi dst,dst,64
1442    
1443     lfd fp0,0(src)
1444     lfd fp1,8(src)
1445     lfd fp2,16(src)
1446     lfd fp3,24(src)
1447     lfd fp4,32(src)
1448     lfd fp5,40(src)
1449     lfd fp6,48(src)
1450     lfd fp7,56(src)
1451     addi src,src,64
1452     stfd fp0,0(dst)
1453     stfd fp1,8(dst)
1454     stfd fp2,16(dst)
1455     stfd fp3,24(dst)
1456     stfd fp4,32(dst)
1457     stfd fp5,40(dst)
1458     stfd fp6,48(dst)
1459     stfd fp7,56(dst)
1460     addi dst,dst,64
1461    
1462     lfd fp0,0(src)
1463     lfd fp1,8(src)
1464     lfd fp2,16(src)
1465     lfd fp3,24(src)
1466     lfd fp4,32(src)
1467     lfd fp5,40(src)
1468     lfd fp6,48(src)
1469     lfd fp7,56(src)
1470     addi src,src,64
1471     stfd fp0,0(dst)
1472     stfd fp1,8(dst)
1473     stfd fp2,16(dst)
1474     stfd fp3,24(dst)
1475     stfd fp4,32(dst)
1476     stfd fp5,40(dst)
1477     stfd fp6,48(dst)
1478     stfd fp7,56(dst)
1479     addi dst,dst,64
1480    
1481     lfd fp0,0(src)
1482     lfd fp1,8(src)
1483     lfd fp2,16(src)
1484     lfd fp3,24(src)
1485     lfd fp4,32(src)
1486     lfd fp5,40(src)
1487     lfd fp6,48(src)
1488     lfd fp7,56(src)
1489     addi src,src,64
1490     stfd fp0,0(dst)
1491     stfd fp1,8(dst)
1492     stfd fp2,16(dst)
1493     stfd fp3,24(dst)
1494     stfd fp4,32(dst)
1495     stfd fp5,40(dst)
1496     stfd fp6,48(dst)
1497     stfd fp7,56(dst)
1498     addi dst,dst,64
1499    
1500     lfd fp0,0(src)
1501     lfd fp1,8(src)
1502     lfd fp2,16(src)
1503     lfd fp3,24(src)
1504     lfd fp4,32(src)
1505     lfd fp5,40(src)
1506     lfd fp6,48(src)
1507     lfd fp7,56(src)
1508     addi src,src,64
1509     stfd fp0,0(dst)
1510     stfd fp1,8(dst)
1511     stfd fp2,16(dst)
1512     stfd fp3,24(dst)
1513     stfd fp4,32(dst)
1514     stfd fp5,40(dst)
1515     stfd fp6,48(dst)
1516     stfd fp7,56(dst)
1517     addi dst,dst,64
1518    
1519     lfd fp0,0(src)
1520     lfd fp1,8(src)
1521     lfd fp2,16(src)
1522     lfd fp3,24(src)
1523     lfd fp4,32(src)
1524     lfd fp5,40(src)
1525     lfd fp6,48(src)
1526     lfd fp7,56(src)
1527     addi src,src,64
1528     stfd fp0,0(dst)
1529     stfd fp1,8(dst)
1530     stfd fp2,16(dst)
1531     stfd fp3,24(dst)
1532     stfd fp4,32(dst)
1533     stfd fp5,40(dst)
1534     stfd fp6,48(dst)
1535     stfd fp7,56(dst)
1536     addi dst,dst,64
1537     blr
1538     }
1539     #endif
1540    
1541    
1542     /*
1543     * Emulate one raster line
1544     */
1545    
1546     int MOS6569::EmulateLine(void)
1547     {
1548     int cycles_left = ThePrefs.NormalCycles; // Cycles left for CPU
1549     bool is_bad_line = false;
1550    
1551     // Get raster counter into local variable for faster access and increment
1552     unsigned int raster = raster_y+1;
1553    
1554     // End of screen reached?
1555     if (raster != TOTAL_RASTERS)
1556     raster_y = raster;
1557     else {
1558     vblank();
1559     raster = 0;
1560     }
1561    
1562     // Trigger raster IRQ if IRQ line reached
1563     if (raster == irq_raster)
1564     raster_irq();
1565    
1566     // In line $30, the DEN bit controls if Bad Lines can occur
1567     if (raster == 0x30)
1568     bad_lines_enabled = ctrl1 & 0x10;
1569    
1570     // Skip frame? Only calculate Bad Lines then
1571     if (frame_skipped) {
1572     if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1573     is_bad_line = true;
1574     cycles_left = ThePrefs.BadLineCycles;
1575     }
1576     goto VIC_nop;
1577     }
1578    
1579     // Within the visible range?
1580     if (raster >= FIRST_DISP_LINE && raster <= LAST_DISP_LINE) {
1581    
1582     // Our output goes here
1583     #ifdef __POWERPC__
1584     uint8 *chunky_ptr = (uint8 *)chunky_tmp;
1585     #else
1586     uint8 *chunky_ptr = chunky_line_start;
1587     #endif
1588    
1589     // Set video counter
1590     vc = vc_base;
1591    
1592     // Bad Line condition?
1593     if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1594    
1595     // Turn on display
1596     display_state = is_bad_line = true;
1597     cycles_left = ThePrefs.BadLineCycles;
1598     rc = 0;
1599    
1600     // Read and latch 40 bytes from video matrix and color RAM
1601     uint8 *mp = matrix_line - 1;
1602     uint8 *cp = color_line - 1;
1603     int vc1 = vc - 1;
1604     uint8 *mbp = matrix_base + vc1;
1605     uint8 *crp = color_ram + vc1;
1606     for (int i=0; i<40; i++) {
1607     *++mp = *++mbp;
1608     *++cp = *++crp;
1609     }
1610     }
1611    
1612     // Handler upper/lower border
1613     if (raster == dy_stop)
1614     border_on = true;
1615     if (raster == dy_start && (ctrl1 & 0x10)) // Don't turn off border if DEN bit cleared
1616     border_on = false;
1617    
1618     if (!border_on) {
1619    
1620     // Display window contents
1621     uint8 *p = chunky_ptr + COL40_XSTART; // Pointer in chunky display buffer
1622     uint8 *r = fore_mask_buf + COL40_XSTART/8; // Pointer in foreground mask buffer
1623     #ifdef ALIGNMENT_CHECK
1624     uint8 *use_p = ((((int)p) & 3) == 0) ? p : text_chunky_buf;
1625     #endif
1626    
1627     {
1628     p--;
1629     uint8 b0cc = b0c_color;
1630     int limit = x_scroll;
1631     for (int i=0; i<limit; i++) // Background on the left if XScroll>0
1632     *++p = b0cc;
1633     p++;
1634     }
1635    
1636     if (display_state) {
1637     switch (display_idx) {
1638    
1639     case 0: // Standard text
1640     #ifndef CAN_ACCESS_UNALIGNED
1641     #ifdef ALIGNMENT_CHECK
1642     el_std_text(use_p, char_base + rc, r);
1643     if (use_p != p)
1644     memcpy(p, use_p, 8*40);
1645     #else
1646     if (x_scroll) {
1647     el_std_text(text_chunky_buf, char_base + rc, r);
1648     memcpy(p, text_chunky_buf, 8*40);
1649     } else
1650     el_std_text(p, char_base + rc, r);
1651     #endif
1652     #else
1653     el_std_text(p, char_base + rc, r);
1654     #endif
1655     break;
1656    
1657     case 1: // Multicolor text
1658     #ifndef CAN_ACCESS_UNALIGNED
1659     #ifdef ALIGNMENT_CHECK
1660     el_mc_text(use_p, char_base + rc, r);
1661     if (use_p != p)
1662     memcpy(p, use_p, 8*40);
1663     #else
1664     if (x_scroll) {
1665     el_mc_text(text_chunky_buf, char_base + rc, r);
1666     memcpy(p, text_chunky_buf, 8*40);
1667     } else
1668     el_mc_text(p, char_base + rc, r);
1669     #endif
1670     #else
1671     el_mc_text(p, char_base + rc, r);
1672     #endif
1673     break;
1674    
1675     case 2: // Standard bitmap
1676     #ifndef CAN_ACCESS_UNALIGNED
1677     #ifdef ALIGNMENT_CHECK
1678     el_std_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1679     if (use_p != p)
1680     memcpy(p, use_p, 8*40);
1681     #else
1682     if (x_scroll) {
1683     el_std_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1684     memcpy(p, text_chunky_buf, 8*40);
1685     } else
1686     el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1687     #endif
1688     #else
1689     el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1690     #endif
1691     break;
1692    
1693     case 3: // Multicolor bitmap
1694     #ifndef CAN_ACCESS_UNALIGNED
1695     #ifdef ALIGNMENT_CHECK
1696     el_mc_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1697     if (use_p != p)
1698     memcpy(p, use_p, 8*40);
1699     #else
1700     if (x_scroll) {
1701     el_mc_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1702     memcpy(p, text_chunky_buf, 8*40);
1703     } else
1704     el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1705     #endif
1706     #else
1707     el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1708     #endif
1709     break;
1710    
1711     case 4: // ECM text
1712     #ifndef CAN_ACCESS_UNALIGNED
1713     #ifdef ALIGNMENT_CHECK
1714     el_ecm_text(use_p, char_base + rc, r);
1715     if (use_p != p)
1716     memcpy(p, use_p, 8*40);
1717     #else
1718     if (x_scroll) {
1719     el_ecm_text(text_chunky_buf, char_base + rc, r);
1720     memcpy(p, text_chunky_buf, 8*40);
1721     } else
1722     el_ecm_text(p, char_base + rc, r);
1723     #endif
1724     #else
1725     el_ecm_text(p, char_base + rc, r);
1726     #endif
1727     break;
1728    
1729     default: // Invalid mode (all black)
1730     memset(p, colors[0], 320);
1731     memset(r, 0, 40);
1732     break;
1733     }
1734     vc += 40;
1735    
1736     } else { // Idle state graphics
1737     switch (display_idx) {
1738    
1739     case 0: // Standard text
1740     case 1: // Multicolor text
1741     case 4: // ECM text
1742     #ifndef CAN_ACCESS_UNALIGNED
1743     #ifdef ALIGNMENT_CHECK
1744     el_std_idle(use_p, r);
1745     if (use_p != p) {memcpy(p, use_p, 8*40);}
1746     #else
1747     if (x_scroll) {
1748     el_std_idle(text_chunky_buf, r);
1749     memcpy(p, text_chunky_buf, 8*40);
1750     } else
1751     el_std_idle(p, r);
1752     #endif
1753     #else
1754     el_std_idle(p, r);
1755     #endif
1756     break;
1757    
1758     case 3: // Multicolor bitmap
1759     #ifndef CAN_ACCESS_UNALIGNED
1760     #ifdef ALIGNMENT_CHECK
1761     el_mc_idle(use_p, r);
1762     if (use_p != p) {memcpy(p, use_p, 8*40);}
1763     #else
1764     if (x_scroll) {
1765     el_mc_idle(text_chunky_buf, r);
1766     memcpy(p, text_chunky_buf, 8*40);
1767     } else
1768     el_mc_idle(p, r);
1769     #endif
1770     #else
1771     el_mc_idle(p, r);
1772     #endif
1773     break;
1774    
1775     default: // Invalid mode (all black)
1776     memset(p, colors[0], 320);
1777     memset(r, 0, 40);
1778     break;
1779     }
1780     }
1781    
1782     // Draw sprites
1783     if (sprite_on && ThePrefs.SpritesOn) {
1784    
1785     // Clear sprite collision buffer
1786     uint32 *lp = (uint32 *)spr_coll_buf - 1;
1787     for (int i=0; i<DISPLAY_X/4; i++)
1788     *++lp = 0;
1789    
1790     el_sprites(chunky_ptr);
1791     }
1792    
1793     // Handle left/right border
1794     uint32 *lp = (uint32 *)chunky_ptr - 1;
1795     uint32 c = ec_color_long;
1796     for (int i=0; i<COL40_XSTART/4; i++)
1797     *++lp = c;
1798     lp = (uint32 *)(chunky_ptr + COL40_XSTOP) - 1;
1799     for (int i=0; i<(DISPLAY_X-COL40_XSTOP)/4; i++)
1800     *++lp = c;
1801     if (!border_40_col) {
1802     c = ec_color;
1803     p = chunky_ptr + COL40_XSTART - 1;
1804     for (int i=0; i<COL38_XSTART-COL40_XSTART; i++)
1805     *++p = c;
1806     p = chunky_ptr + COL38_XSTOP - 1;
1807     for (int i=0; i<COL40_XSTOP-COL38_XSTOP; i++)
1808     *++p = c;
1809     }
1810    
1811     #if 0
1812     if (is_bad_line) {
1813     chunky_ptr[DISPLAY_X-2] = colors[7];
1814     chunky_ptr[DISPLAY_X-3] = colors[7];
1815     }
1816     if (rc & 1) {
1817     chunky_ptr[DISPLAY_X-4] = colors[1];
1818     chunky_ptr[DISPLAY_X-5] = colors[1];
1819     }
1820     if (rc & 2) {
1821     chunky_ptr[DISPLAY_X-6] = colors[1];
1822     chunky_ptr[DISPLAY_X-7] = colors[1];
1823     }
1824     if (rc & 4) {
1825     chunky_ptr[DISPLAY_X-8] = colors[1];
1826     chunky_ptr[DISPLAY_X-9] = colors[1];
1827     }
1828     if (ctrl1 & 0x40) {
1829     chunky_ptr[DISPLAY_X-10] = colors[5];
1830     chunky_ptr[DISPLAY_X-11] = colors[5];
1831     }
1832     if (ctrl1 & 0x20) {
1833     chunky_ptr[DISPLAY_X-12] = colors[3];
1834     chunky_ptr[DISPLAY_X-13] = colors[3];
1835     }
1836     if (ctrl2 & 0x10) {
1837     chunky_ptr[DISPLAY_X-14] = colors[2];
1838     chunky_ptr[DISPLAY_X-15] = colors[2];
1839     }
1840     #endif
1841     } else {
1842    
1843     // Display border
1844     uint32 *lp = (uint32 *)chunky_ptr - 1;
1845     uint32 c = ec_color_long;
1846     for (int i=0; i<DISPLAY_X/4; i++)
1847     *++lp = c;
1848     }
1849    
1850     #ifdef __POWERPC__
1851     // Copy temporary buffer to bitmap
1852     fastcopy(chunky_line_start, (uint8 *)chunky_tmp);
1853     #endif
1854    
1855     // Increment pointer in chunky buffer
1856     chunky_line_start += xmod;
1857    
1858     // Increment row counter, go to idle state on overflow
1859     if (rc == 7) {
1860     display_state = false;
1861     vc_base = vc;
1862     } else
1863     rc++;
1864    
1865     if (raster >= FIRST_DMA_LINE-1 && raster <= LAST_DMA_LINE-1 && (((raster+1) & 7) == y_scroll) && bad_lines_enabled)
1866     rc = 0;
1867     }
1868    
1869     VIC_nop:
1870     // Skip this if all sprites are off
1871     if (me | sprite_on)
1872     cycles_left -= el_update_mc(raster);
1873    
1874     return cycles_left;
1875     }