ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC.cpp
Revision: 1.5
Committed: 2010-04-21T20:42:09Z (14 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +3 -2 lines
Log Message:
added missing initialization

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * VIC.cpp - 6569R5 emulation (line based)
3     *
4 cebix 1.5 * Frodo Copyright (C) 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 cebix 1.5 static uint8 bad_lines_enabled; // Flag: Bad Lines enabled for this frame
255 cebix 1.1 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 cebix 1.5 bad_lines_enabled = false;
336 cebix 1.1 lp_triggered = false;
337    
338     sprite_on = 0;
339     for (i=0; i<8; i++)
340     mc[i] = 63;
341    
342     frame_skipped = false;
343     skip_counter = 1;
344    
345     // Clear foreground mask
346     memset(fore_mask_buf, 0, DISPLAY_X/8);
347    
348     // Preset colors to black
349     disp->InitColors(colors);
350     init_text_color_table(colors);
351     ec_color = b0c_color = b1c_color = b2c_color = b3c_color = mm0_color = mm1_color = colors[0];
352     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
353     for (i=0; i<8; i++) spr_color[i] = colors[0];
354     }
355    
356    
357     /*
358     * Reinitialize the colors table for when the palette has changed
359     */
360    
361     void MOS6569::ReInitColors(void)
362     {
363     int i;
364    
365     // Build inverse color table.
366     uint8 xlate_colors[256];
367     memset(xlate_colors, 0, sizeof(xlate_colors));
368     for (i = 0; i < 16; i++)
369     xlate_colors[colors[i]] = i;
370    
371     // Get the new colors.
372     the_display->InitColors(colors);
373     init_text_color_table(colors);
374    
375     // Build color translation table.
376     for (i = 0; i < 256; i++)
377     xlate_colors[i] = colors[xlate_colors[i]];
378    
379     // Translate all the old colors variables.
380     ec_color = colors[ec];
381     ec_color_long = ec_color | (ec_color << 8) | (ec_color << 16) | (ec_color << 24);
382     b0c_color = colors[b0c];
383     b1c_color = colors[b1c];
384     b2c_color = colors[b2c];
385     b3c_color = colors[b3c];
386     mm0_color = colors[mm0];
387     mm1_color = colors[mm1];
388     for (i = 0; i < 8; i++)
389     spr_color[i] = colors[sc[i]];
390     mc_color_lookup[0] = b0c_color | (b0c_color << 8);
391     mc_color_lookup[1] = b1c_color | (b1c_color << 8);
392     mc_color_lookup[2] = b2c_color | (b2c_color << 8);
393    
394     // Translate the chunky buffer.
395     uint8 *scanline = the_display->BitmapBase();
396     for (int y = 0; y < DISPLAY_Y; y++) {
397     for (int x = 0; x < DISPLAY_X; x++)
398     scanline[x] = xlate_colors[scanline[x]];
399     scanline += xmod;
400     }
401     }
402    
403     #ifdef GLOBAL_VARS
404     static void make_mc_table(void)
405     #else
406     void MOS6569::make_mc_table(void)
407     #endif
408     {
409     mc_color_lookup[0] = b0c_color | (b0c_color << 8);
410     mc_color_lookup[1] = b1c_color | (b1c_color << 8);
411     mc_color_lookup[2] = b2c_color | (b2c_color << 8);
412     }
413    
414    
415     /*
416     * Convert video address to pointer
417     */
418    
419     #ifdef GLOBAL_VARS
420     static inline uint8 *get_physical(uint16 adr)
421     #else
422     inline uint8 *MOS6569::get_physical(uint16 adr)
423     #endif
424     {
425     int va = adr | cia_vabase;
426     if ((va & 0x7000) == 0x1000)
427     return char_rom + (va & 0x0fff);
428     else
429     return ram + va;
430     }
431    
432    
433     /*
434     * Get VIC state
435     */
436    
437     void MOS6569::GetState(MOS6569State *vd)
438     {
439     int i;
440    
441     vd->m0x = mx[0] & 0xff; vd->m0y = my[0];
442     vd->m1x = mx[1] & 0xff; vd->m1y = my[1];
443     vd->m2x = mx[2] & 0xff; vd->m2y = my[2];
444     vd->m3x = mx[3] & 0xff; vd->m3y = my[3];
445     vd->m4x = mx[4] & 0xff; vd->m4y = my[4];
446     vd->m5x = mx[5] & 0xff; vd->m5y = my[5];
447     vd->m6x = mx[6] & 0xff; vd->m6y = my[6];
448     vd->m7x = mx[7] & 0xff; vd->m7y = my[7];
449     vd->mx8 = mx8;
450    
451     vd->ctrl1 = (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
452     vd->raster = raster_y & 0xff;
453     vd->lpx = lpx; vd->lpy = lpy;
454     vd->ctrl2 = ctrl2;
455     vd->vbase = vbase;
456     vd->irq_flag = irq_flag;
457     vd->irq_mask = irq_mask;
458    
459     vd->me = me; vd->mxe = mxe; vd->mye = mye; vd->mdp = mdp; vd->mmc = mmc;
460     vd->mm = clx_spr; vd->md = clx_bgr;
461    
462     vd->ec = ec;
463     vd->b0c = b0c; vd->b1c = b1c; vd->b2c = b2c; vd->b3c = b3c;
464     vd->mm0 = mm0; vd->mm1 = mm1;
465     vd->m0c = sc[0]; vd->m1c = sc[1];
466     vd->m2c = sc[2]; vd->m3c = sc[3];
467     vd->m4c = sc[4]; vd->m5c = sc[5];
468     vd->m6c = sc[6]; vd->m7c = sc[7];
469    
470     vd->pad0 = 0;
471     vd->irq_raster = irq_raster;
472     vd->vc = vc;
473     vd->vc_base = vc_base;
474     vd->rc = rc;
475     vd->spr_dma = vd->spr_disp = sprite_on;
476     for (i=0; i<8; i++)
477     vd->mc[i] = vd->mc_base[i] = mc[i];
478     vd->display_state = display_state;
479     vd->bad_line = raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled;
480     vd->bad_line_enable = bad_lines_enabled;
481     vd->lp_triggered = lp_triggered;
482     vd->border_on = border_on;
483    
484     vd->bank_base = cia_vabase;
485     vd->matrix_base = ((vbase & 0xf0) << 6) | cia_vabase;
486     vd->char_base = ((vbase & 0x0e) << 10) | cia_vabase;
487     vd->bitmap_base = ((vbase & 0x08) << 10) | cia_vabase;
488     for (i=0; i<8; i++)
489     vd->sprite_base[i] = (matrix_base[0x3f8 + i] << 6) | cia_vabase;
490    
491     vd->cycle = 1;
492     vd->raster_x = 0;
493     vd->ml_index = 0;
494     vd->ref_cnt = 0xff;
495     vd->last_vic_byte = 0;
496     vd->ud_border_on = border_on;
497     }
498    
499    
500     /*
501     * Set VIC state (only works if in VBlank)
502     */
503    
504     void MOS6569::SetState(MOS6569State *vd)
505     {
506     int i, j;
507    
508     mx[0] = vd->m0x; my[0] = vd->m0y;
509     mx[1] = vd->m1x; my[1] = vd->m1y;
510     mx[2] = vd->m2x; my[2] = vd->m2y;
511     mx[3] = vd->m3x; my[3] = vd->m3y;
512     mx[4] = vd->m4x; my[4] = vd->m4y;
513     mx[5] = vd->m5x; my[5] = vd->m5y;
514     mx[6] = vd->m6x; my[6] = vd->m6y;
515     mx[7] = vd->m7x; my[7] = vd->m7y;
516     mx8 = vd->mx8;
517     for (i=0, j=1; i<8; i++, j<<=1) {
518     if (mx8 & j)
519     mx[i] |= 0x100;
520     else
521     mx[i] &= 0xff;
522     }
523    
524     ctrl1 = vd->ctrl1;
525     ctrl2 = vd->ctrl2;
526     x_scroll = ctrl2 & 7;
527     y_scroll = ctrl1 & 7;
528     if (ctrl1 & 8) {
529     dy_start = ROW25_YSTART;
530     dy_stop = ROW25_YSTOP;
531     } else {
532     dy_start = ROW24_YSTART;
533     dy_stop = ROW24_YSTOP;
534     }
535     border_40_col = ctrl2 & 8;
536     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
537    
538     raster_y = 0;
539     lpx = vd->lpx; lpy = vd->lpy;
540    
541     vbase = vd->vbase;
542     cia_vabase = vd->bank_base;
543     matrix_base = get_physical((vbase & 0xf0) << 6);
544     char_base = get_physical((vbase & 0x0e) << 10);
545     bitmap_base = get_physical((vbase & 0x08) << 10);
546    
547     irq_flag = vd->irq_flag;
548     irq_mask = vd->irq_mask;
549    
550     me = vd->me; mxe = vd->mxe; mye = vd->mye; mdp = vd->mdp; mmc = vd->mmc;
551     clx_spr = vd->mm; clx_bgr = vd->md;
552    
553     ec = vd->ec;
554     ec_color = colors[ec];
555     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
556    
557     b0c = vd->b0c; b1c = vd->b1c; b2c = vd->b2c; b3c = vd->b3c;
558     b0c_color = colors[b0c];
559     b1c_color = colors[b1c];
560     b2c_color = colors[b2c];
561     b3c_color = colors[b3c];
562     make_mc_table();
563    
564     mm0 = vd->mm0; mm1 = vd->mm1;
565     mm0_color = colors[mm0];
566     mm1_color = colors[mm1];
567    
568     sc[0] = vd->m0c; sc[1] = vd->m1c;
569     sc[2] = vd->m2c; sc[3] = vd->m3c;
570     sc[4] = vd->m4c; sc[5] = vd->m5c;
571     sc[6] = vd->m6c; sc[7] = vd->m7c;
572     for (i=0; i<8; i++)
573     spr_color[i] = colors[sc[i]];
574    
575     irq_raster = vd->irq_raster;
576     vc = vd->vc;
577     vc_base = vd->vc_base;
578     rc = vd->rc;
579     sprite_on = vd->spr_dma;
580     for (i=0; i<8; i++)
581     mc[i] = vd->mc[i];
582     display_state = vd->display_state;
583     bad_lines_enabled = vd->bad_line_enable;
584     lp_triggered = vd->lp_triggered;
585     border_on = vd->border_on;
586     }
587    
588    
589     /*
590     * Trigger raster IRQ
591     */
592    
593     #ifdef GLOBAL_VARS
594     static inline void raster_irq(void)
595     #else
596     inline void MOS6569::raster_irq(void)
597     #endif
598     {
599     irq_flag |= 0x01;
600     if (irq_mask & 0x01) {
601     irq_flag |= 0x80;
602     the_cpu->TriggerVICIRQ();
603     }
604     }
605    
606    
607     /*
608     * Read from VIC register
609     */
610    
611     uint8 MOS6569::ReadRegister(uint16 adr)
612     {
613     switch (adr) {
614     case 0x00: case 0x02: case 0x04: case 0x06:
615     case 0x08: case 0x0a: case 0x0c: case 0x0e:
616     return mx[adr >> 1];
617    
618     case 0x01: case 0x03: case 0x05: case 0x07:
619     case 0x09: case 0x0b: case 0x0d: case 0x0f:
620     return my[adr >> 1];
621    
622     case 0x10: // Sprite X position MSB
623     return mx8;
624    
625     case 0x11: // Control register 1
626     return (ctrl1 & 0x7f) | ((raster_y & 0x100) >> 1);
627    
628     case 0x12: // Raster counter
629     return raster_y;
630    
631     case 0x13: // Light pen X
632     return lpx;
633    
634     case 0x14: // Light pen Y
635     return lpy;
636    
637     case 0x15: // Sprite enable
638     return me;
639    
640     case 0x16: // Control register 2
641     return ctrl2 | 0xc0;
642    
643     case 0x17: // Sprite Y expansion
644     return mye;
645    
646     case 0x18: // Memory pointers
647     return vbase | 0x01;
648    
649     case 0x19: // IRQ flags
650     return irq_flag | 0x70;
651    
652     case 0x1a: // IRQ mask
653     return irq_mask | 0xf0;
654    
655     case 0x1b: // Sprite data priority
656     return mdp;
657    
658     case 0x1c: // Sprite multicolor
659     return mmc;
660    
661     case 0x1d: // Sprite X expansion
662     return mxe;
663    
664     case 0x1e:{ // Sprite-sprite collision
665     uint8 ret = clx_spr;
666     clx_spr = 0; // Read and clear
667     return ret;
668     }
669    
670     case 0x1f:{ // Sprite-background collision
671     uint8 ret = clx_bgr;
672     clx_bgr = 0; // Read and clear
673     return ret;
674     }
675    
676     case 0x20: return ec | 0xf0;
677     case 0x21: return b0c | 0xf0;
678     case 0x22: return b1c | 0xf0;
679     case 0x23: return b2c | 0xf0;
680     case 0x24: return b3c | 0xf0;
681     case 0x25: return mm0 | 0xf0;
682     case 0x26: return mm1 | 0xf0;
683    
684     case 0x27: case 0x28: case 0x29: case 0x2a:
685     case 0x2b: case 0x2c: case 0x2d: case 0x2e:
686     return sc[adr - 0x27] | 0xf0;
687    
688     default:
689     return 0xff;
690     }
691     }
692    
693    
694     /*
695     * Write to VIC register
696     */
697    
698     void MOS6569::WriteRegister(uint16 adr, uint8 byte)
699     {
700     switch (adr) {
701     case 0x00: case 0x02: case 0x04: case 0x06:
702     case 0x08: case 0x0a: case 0x0c: case 0x0e:
703     mx[adr >> 1] = (mx[adr >> 1] & 0xff00) | byte;
704     break;
705    
706     case 0x10:{
707     int i, j;
708     mx8 = byte;
709     for (i=0, j=1; i<8; i++, j<<=1) {
710     if (mx8 & j)
711     mx[i] |= 0x100;
712     else
713     mx[i] &= 0xff;
714     }
715     break;
716     }
717    
718     case 0x01: case 0x03: case 0x05: case 0x07:
719     case 0x09: case 0x0b: case 0x0d: case 0x0f:
720     my[adr >> 1] = byte;
721     break;
722    
723     case 0x11:{ // Control register 1
724     ctrl1 = byte;
725     y_scroll = byte & 7;
726    
727     uint16 new_irq_raster = (irq_raster & 0xff) | ((byte & 0x80) << 1);
728     if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
729     raster_irq();
730     irq_raster = new_irq_raster;
731    
732     if (byte & 8) {
733     dy_start = ROW25_YSTART;
734     dy_stop = ROW25_YSTOP;
735     } else {
736     dy_start = ROW24_YSTART;
737     dy_stop = ROW24_YSTOP;
738     }
739    
740     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
741     break;
742     }
743    
744     case 0x12:{ // Raster counter
745     uint16 new_irq_raster = (irq_raster & 0xff00) | byte;
746     if (irq_raster != new_irq_raster && raster_y == new_irq_raster)
747     raster_irq();
748     irq_raster = new_irq_raster;
749     break;
750     }
751    
752     case 0x15: // Sprite enable
753     me = byte;
754     break;
755    
756     case 0x16: // Control register 2
757     ctrl2 = byte;
758     x_scroll = byte & 7;
759     border_40_col = byte & 8;
760     display_idx = ((ctrl1 & 0x60) | (ctrl2 & 0x10)) >> 4;
761     break;
762    
763     case 0x17: // Sprite Y expansion
764     mye = byte;
765     break;
766    
767     case 0x18: // Memory pointers
768     vbase = byte;
769     matrix_base = get_physical((byte & 0xf0) << 6);
770     char_base = get_physical((byte & 0x0e) << 10);
771     bitmap_base = get_physical((byte & 0x08) << 10);
772     break;
773    
774     case 0x19: // IRQ flags
775     irq_flag = irq_flag & (~byte & 0x0f);
776     the_cpu->ClearVICIRQ(); // Clear interrupt (hack!)
777     if (irq_flag & irq_mask) // Set master bit if allowed interrupt still pending
778     irq_flag |= 0x80;
779     break;
780    
781     case 0x1a: // IRQ mask
782     irq_mask = byte & 0x0f;
783     if (irq_flag & irq_mask) { // Trigger interrupt if pending and now allowed
784     irq_flag |= 0x80;
785     the_cpu->TriggerVICIRQ();
786     } else {
787     irq_flag &= 0x7f;
788     the_cpu->ClearVICIRQ();
789     }
790     break;
791    
792     case 0x1b: // Sprite data priority
793     mdp = byte;
794     break;
795    
796     case 0x1c: // Sprite multicolor
797     mmc = byte;
798     break;
799    
800     case 0x1d: // Sprite X expansion
801     mxe = byte;
802     break;
803    
804     case 0x20:
805     ec_color = colors[ec = byte];
806     ec_color_long = (ec_color << 24) | (ec_color << 16) | (ec_color << 8) | ec_color;
807     break;
808    
809     case 0x21:
810     if (b0c != byte) {
811     b0c_color = colors[b0c = byte & 0xF];
812     make_mc_table();
813     }
814     break;
815    
816     case 0x22:
817     if (b1c != byte) {
818     b1c_color = colors[b1c = byte & 0xF];
819     make_mc_table();
820     }
821     break;
822    
823     case 0x23:
824     if (b2c != byte) {
825     b2c_color = colors[b2c = byte & 0xF];
826     make_mc_table();
827     }
828     break;
829    
830     case 0x24: b3c_color = colors[b3c = byte & 0xF]; break;
831     case 0x25: mm0_color = colors[mm0 = byte]; break;
832     case 0x26: mm1_color = colors[mm1 = byte]; break;
833    
834     case 0x27: case 0x28: case 0x29: case 0x2a:
835     case 0x2b: case 0x2c: case 0x2d: case 0x2e:
836     spr_color[adr - 0x27] = colors[sc[adr - 0x27] = byte];
837     break;
838     }
839     }
840    
841    
842     /*
843     * CIA VA14/15 has changed
844     */
845    
846     void MOS6569::ChangedVA(uint16 new_va)
847     {
848     cia_vabase = new_va << 14;
849     WriteRegister(0x18, vbase); // Force update of memory pointers
850     }
851    
852    
853     /*
854     * Trigger lightpen interrupt, latch lightpen coordinates
855     */
856    
857     void MOS6569::TriggerLightpen(void)
858     {
859     if (!lp_triggered) { // Lightpen triggers only once per frame
860     lp_triggered = true;
861    
862     lpx = 0; // Latch current coordinates
863     lpy = raster_y;
864    
865     irq_flag |= 0x08; // Trigger IRQ
866     if (irq_mask & 0x08) {
867     irq_flag |= 0x80;
868     the_cpu->TriggerVICIRQ();
869     }
870     }
871     }
872    
873    
874     /*
875     * VIC vertical blank: Reset counters and redraw screen
876     */
877    
878     #ifdef GLOBAL_VARS
879     static inline void vblank(void)
880     #else
881     inline void MOS6569::vblank(void)
882     #endif
883     {
884     raster_y = vc_base = 0;
885     lp_triggered = false;
886    
887     if (!(frame_skipped = --skip_counter))
888     skip_counter = ThePrefs.SkipFrames;
889    
890     the_c64->VBlank(!frame_skipped);
891    
892     // Get bitmap pointer for next frame. This must be done
893     // after calling the_c64->VBlank() because the preferences
894     // and screen configuration may have been changed there
895     chunky_line_start = the_display->BitmapBase();
896     xmod = the_display->BitmapXMod();
897     }
898    
899    
900     #ifdef __riscos__
901     #include "el_Acorn.h"
902     #else
903    
904     #ifdef GLOBAL_VARS
905     static inline void el_std_text(uint8 *p, uint8 *q, uint8 *r)
906     #else
907     inline void MOS6569::el_std_text(uint8 *p, uint8 *q, uint8 *r)
908     #endif
909     {
910     unsigned int b0cc = b0c;
911     #ifdef __POWERPC__
912     double *dp = (double *)p - 1;
913     #else
914     uint32 *lp = (uint32 *)p;
915     #endif
916     uint8 *cp = color_line;
917     uint8 *mp = matrix_line;
918    
919     // Loop for 40 characters
920     for (int i=0; i<40; i++) {
921     uint8 color = cp[i];
922     uint8 data = r[i] = q[mp[i] << 3];
923    
924     #ifdef __POWERPC__
925     *++dp = TextColorTable[color][b0cc][data].b;
926     #else
927     *lp++ = TextColorTable[color][b0cc][data][0].b;
928     *lp++ = TextColorTable[color][b0cc][data][1].b;
929     #endif
930     }
931     }
932    
933    
934     #ifdef GLOBAL_VARS
935     static inline void el_mc_text(uint8 *p, uint8 *q, uint8 *r)
936     #else
937     inline void MOS6569::el_mc_text(uint8 *p, uint8 *q, uint8 *r)
938     #endif
939     {
940     uint16 *wp = (uint16 *)p;
941     uint8 *cp = color_line;
942     uint8 *mp = matrix_line;
943     uint16 *mclp = mc_color_lookup;
944    
945     // Loop for 40 characters
946     for (int i=0; i<40; i++) {
947     uint8 data = q[mp[i] << 3];
948    
949     if (cp[i] & 8) {
950     uint8 color = colors[cp[i] & 7];
951     r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
952     mclp[3] = color | (color << 8);
953     *wp++ = mclp[(data >> 6) & 3];
954     *wp++ = mclp[(data >> 4) & 3];
955     *wp++ = mclp[(data >> 2) & 3];
956     *wp++ = mclp[(data >> 0) & 3];
957    
958     } else { // Standard mode in multicolor mode
959     uint8 color = cp[i];
960     r[i] = data;
961     #ifdef __POWERPC__
962     *(double *)wp = TextColorTable[color][b0c][data].b;
963     wp += 4;
964     #else
965     *(uint32 *)wp = TextColorTable[color][b0c][data][0].b;
966     wp += 2;
967     *(uint32 *)wp = TextColorTable[color][b0c][data][1].b;
968     wp += 2;
969     #endif
970     }
971     }
972     }
973    
974    
975     #ifdef GLOBAL_VARS
976     static inline void el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
977     #else
978     inline void MOS6569::el_std_bitmap(uint8 *p, uint8 *q, uint8 *r)
979     #endif
980     {
981     #ifdef __POWERPC__
982     double *dp = (double *)p-1;
983     #else
984     uint32 *lp = (uint32 *)p;
985     #endif
986     uint8 *mp = matrix_line;
987    
988     // Loop for 40 characters
989     for (int i=0; i<40; i++, q+=8) {
990     uint8 data = r[i] = *q;
991     uint8 color = mp[i] >> 4;
992     uint8 bcolor = mp[i] & 15;
993    
994     #ifdef __POWERPC__
995     *++dp = TextColorTable[color][bcolor][data].b;
996     #else
997     *lp++ = TextColorTable[color][bcolor][data][0].b;
998     *lp++ = TextColorTable[color][bcolor][data][1].b;
999     #endif
1000     }
1001     }
1002    
1003    
1004     #ifdef GLOBAL_VARS
1005     static inline void el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
1006     #else
1007     inline void MOS6569::el_mc_bitmap(uint8 *p, uint8 *q, uint8 *r)
1008     #endif
1009     {
1010     uint16 lookup[4];
1011     uint16 *wp = (uint16 *)p - 1;
1012     uint8 *cp = color_line;
1013     uint8 *mp = matrix_line;
1014    
1015     #ifdef __GNU_C__
1016     &lookup; /* Statement with no effect other than preventing GCC from
1017     * putting the array in a register, which generates
1018     * spectacularly bad code. */
1019     #endif
1020    
1021     lookup[0] = (b0c_color << 8) | b0c_color;
1022    
1023     // Loop for 40 characters
1024     for (int i=0; i<40; i++, q+=8) {
1025     uint8 color, acolor, bcolor;
1026    
1027     color = colors[mp[i] >> 4];
1028     lookup[1] = (color << 8) | color;
1029     bcolor = colors[mp[i]];
1030     lookup[2] = (bcolor << 8) | bcolor;
1031     acolor = colors[cp[i]];
1032     lookup[3] = (acolor << 8) | acolor;
1033    
1034     uint8 data = *q;
1035     r[i] = (data & 0xaa) | (data & 0xaa) >> 1;
1036    
1037     *++wp = lookup[(data >> 6) & 3];
1038     *++wp = lookup[(data >> 4) & 3];
1039     *++wp = lookup[(data >> 2) & 3];
1040     *++wp = lookup[(data >> 0) & 3];
1041     }
1042     }
1043    
1044    
1045     #ifdef GLOBAL_VARS
1046     static inline void el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1047     #else
1048     inline void MOS6569::el_ecm_text(uint8 *p, uint8 *q, uint8 *r)
1049     #endif
1050     {
1051     #ifdef __POWERPC__
1052     double *dp = (double *)p - 1;
1053     #else
1054     uint32 *lp = (uint32 *)p;
1055     #endif
1056     uint8 *cp = color_line;
1057     uint8 *mp = matrix_line;
1058     uint8 *bcp = &b0c;
1059    
1060     // Loop for 40 characters
1061     for (int i=0; i<40; i++) {
1062     uint8 data = r[i] = mp[i];
1063     uint8 color = cp[i];
1064     uint8 bcolor = bcp[(data >> 6) & 3];
1065    
1066     data = q[(data & 0x3f) << 3];
1067     #ifdef __POWERPC__
1068     *++dp = TextColorTable[color][bcolor][data].b;
1069     #else
1070     *lp++ = TextColorTable[color][bcolor][data][0].b;
1071     *lp++ = TextColorTable[color][bcolor][data][1].b;
1072     #endif
1073     }
1074     }
1075    
1076    
1077     #ifdef GLOBAL_VARS
1078     static inline void el_std_idle(uint8 *p, uint8 *r)
1079     #else
1080     inline void MOS6569::el_std_idle(uint8 *p, uint8 *r)
1081     #endif
1082     {
1083     #ifdef __POWERPC__
1084     uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1085     double *dp = (double *)p - 1;
1086     double conv = TextColorTable[0][b0c][data].b;
1087     r--;
1088    
1089     for (int i=0; i<40; i++) {
1090     *++dp = conv;
1091     *++r = data;
1092     }
1093     #else
1094     uint8 data = *get_physical(ctrl1 & 0x40 ? 0x39ff : 0x3fff);
1095     uint32 *lp = (uint32 *)p;
1096     uint32 conv0 = TextColorTable[0][b0c][data][0].b;
1097     uint32 conv1 = TextColorTable[0][b0c][data][1].b;
1098    
1099     for (int i=0; i<40; i++) {
1100     *lp++ = conv0;
1101     *lp++ = conv1;
1102     *r++ = data;
1103     }
1104     #endif
1105     }
1106    
1107    
1108     #ifdef GLOBAL_VARS
1109     static inline void el_mc_idle(uint8 *p, uint8 *r)
1110     #else
1111     inline void MOS6569::el_mc_idle(uint8 *p, uint8 *r)
1112     #endif
1113     {
1114     uint8 data = *get_physical(0x3fff);
1115     uint32 *lp = (uint32 *)p - 1;
1116     r--;
1117    
1118     uint16 lookup[4];
1119     lookup[0] = (b0c_color << 8) | b0c_color;
1120     lookup[1] = lookup[2] = lookup[3] = colors[0];
1121    
1122     uint16 conv0 = (lookup[(data >> 6) & 3] << 16) | lookup[(data >> 4) & 3];
1123     uint16 conv1 = (lookup[(data >> 2) & 3] << 16) | lookup[(data >> 0) & 3];
1124    
1125     for (int i=0; i<40; i++) {
1126     *++lp = conv0;
1127     *++lp = conv1;
1128     *++r = data;
1129     }
1130     }
1131    
1132     #endif //__riscos__
1133    
1134    
1135     #ifdef GLOBAL_VARS
1136     static inline void el_sprites(uint8 *chunky_ptr)
1137     #else
1138     inline void MOS6569::el_sprites(uint8 *chunky_ptr)
1139     #endif
1140     {
1141     int i;
1142     int snum, sbit; // Sprite number/bit mask
1143     int spr_coll=0, gfx_coll=0;
1144    
1145     // Draw each active sprite
1146     for (snum=0, sbit=1; snum<8; snum++, sbit<<=1)
1147     if ((sprite_on & sbit) && mx[snum] < DISPLAY_X-32) {
1148     int spr_mask_pos; // Sprite bit position in fore_mask_buf
1149     uint32 sdata, fore_mask;
1150    
1151     uint8 *p = chunky_ptr + mx[snum] + 8;
1152     uint8 *q = spr_coll_buf + mx[snum] + 8;
1153    
1154     uint8 *sdatap = get_physical(matrix_base[0x3f8 + snum] << 6 | mc[snum]);
1155     sdata = (*sdatap << 24) | (*(sdatap+1) << 16) | (*(sdatap+2) << 8);
1156    
1157     uint8 color = spr_color[snum];
1158    
1159     spr_mask_pos = mx[snum] + 8 - x_scroll;
1160    
1161     uint8 *fmbp = fore_mask_buf + (spr_mask_pos / 8);
1162     int sshift = spr_mask_pos & 7;
1163     fore_mask = (((*(fmbp+0) << 24) | (*(fmbp+1) << 16) | (*(fmbp+2) << 8)
1164     | (*(fmbp+3))) << sshift) | (*(fmbp+4) >> (8-sshift));
1165    
1166     if (mxe & sbit) { // X-expanded
1167     if (mx[snum] >= DISPLAY_X-56)
1168     continue;
1169    
1170     uint32 sdata_l = 0, sdata_r = 0, fore_mask_r;
1171     fore_mask_r = (((*(fmbp+4) << 24) | (*(fmbp+5) << 16) | (*(fmbp+6) << 8)
1172     | (*(fmbp+7))) << sshift) | (*(fmbp+8) >> (8-sshift));
1173    
1174     if (mmc & sbit) { // Multicolor mode
1175     uint32 plane0_l, plane0_r, plane1_l, plane1_r;
1176    
1177     // Expand sprite data
1178     sdata_l = MultiExpTable[sdata >> 24 & 0xff] << 16 | MultiExpTable[sdata >> 16 & 0xff];
1179     sdata_r = MultiExpTable[sdata >> 8 & 0xff] << 16;
1180    
1181     // Convert sprite chunky pixels to bitplanes
1182     plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
1183     plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
1184     plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
1185     plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
1186    
1187     // Collision with graphics?
1188     if ((fore_mask & (plane0_l | plane1_l)) || (fore_mask_r & (plane0_r | plane1_r))) {
1189     gfx_coll |= sbit;
1190     if (mdp & sbit) {
1191     plane0_l &= ~fore_mask; // Mask sprite if in background
1192     plane1_l &= ~fore_mask;
1193     plane0_r &= ~fore_mask_r;
1194     plane1_r &= ~fore_mask_r;
1195     }
1196     }
1197    
1198     // Paint sprite
1199     for (i=0; i<32; i++, plane0_l<<=1, plane1_l<<=1) {
1200     uint8 col;
1201     if (plane1_l & 0x80000000) {
1202     if (plane0_l & 0x80000000)
1203     col = mm1_color;
1204     else
1205     col = color;
1206     } else {
1207     if (plane0_l & 0x80000000)
1208     col = mm0_color;
1209     else
1210     continue;
1211     }
1212     if (q[i])
1213     spr_coll |= q[i] | sbit;
1214     else {
1215     p[i] = col;
1216     q[i] = sbit;
1217     }
1218     }
1219     for (; i<48; i++, plane0_r<<=1, plane1_r<<=1) {
1220     uint8 col;
1221     if (plane1_r & 0x80000000) {
1222     if (plane0_r & 0x80000000)
1223     col = mm1_color;
1224     else
1225     col = color;
1226     } else {
1227     if (plane0_r & 0x80000000)
1228     col = mm0_color;
1229     else
1230     continue;
1231     }
1232     if (q[i])
1233     spr_coll |= q[i] | sbit;
1234     else {
1235     p[i] = col;
1236     q[i] = sbit;
1237     }
1238     }
1239    
1240     } else { // Standard mode
1241    
1242     // Expand sprite data
1243     sdata_l = ExpTable[sdata >> 24 & 0xff] << 16 | ExpTable[sdata >> 16 & 0xff];
1244     sdata_r = ExpTable[sdata >> 8 & 0xff] << 16;
1245    
1246     // Collision with graphics?
1247     if ((fore_mask & sdata_l) || (fore_mask_r & sdata_r)) {
1248     gfx_coll |= sbit;
1249     if (mdp & sbit) {
1250     sdata_l &= ~fore_mask; // Mask sprite if in background
1251     sdata_r &= ~fore_mask_r;
1252     }
1253     }
1254    
1255     // Paint sprite
1256     for (i=0; i<32; i++, sdata_l<<=1)
1257     if (sdata_l & 0x80000000) {
1258     if (q[i]) // Collision with sprite?
1259     spr_coll |= q[i] | sbit;
1260     else { // Draw pixel if no collision
1261     p[i] = color;
1262     q[i] = sbit;
1263     }
1264     }
1265     for (; i<48; i++, sdata_r<<=1)
1266     if (sdata_r & 0x80000000) {
1267     if (q[i]) // Collision with sprite?
1268     spr_coll |= q[i] | sbit;
1269     else { // Draw pixel if no collision
1270     p[i] = color;
1271     q[i] = sbit;
1272     }
1273     }
1274     }
1275    
1276     } else // Unexpanded
1277    
1278     if (mmc & sbit) { // Multicolor mode
1279     uint32 plane0, plane1;
1280    
1281     // Convert sprite chunky pixels to bitplanes
1282     plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
1283     plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
1284    
1285     // Collision with graphics?
1286     if (fore_mask & (plane0 | plane1)) {
1287     gfx_coll |= sbit;
1288     if (mdp & sbit) {
1289     plane0 &= ~fore_mask; // Mask sprite if in background
1290     plane1 &= ~fore_mask;
1291     }
1292     }
1293    
1294     // Paint sprite
1295     for (i=0; i<24; i++, plane0<<=1, plane1<<=1) {
1296     uint8 col;
1297     if (plane1 & 0x80000000) {
1298     if (plane0 & 0x80000000)
1299     col = mm1_color;
1300     else
1301     col = color;
1302     } else {
1303     if (plane0 & 0x80000000)
1304     col = mm0_color;
1305     else
1306     continue;
1307     }
1308     if (q[i])
1309     spr_coll |= q[i] | sbit;
1310     else {
1311     p[i] = col;
1312     q[i] = sbit;
1313     }
1314     }
1315    
1316     } else { // Standard mode
1317    
1318     // Collision with graphics?
1319     if (fore_mask & sdata) {
1320     gfx_coll |= sbit;
1321     if (mdp & sbit)
1322     sdata &= ~fore_mask; // Mask sprite if in background
1323     }
1324    
1325     // Paint sprite
1326     for (i=0; i<24; i++, sdata<<=1)
1327     if (sdata & 0x80000000) {
1328     if (q[i]) { // Collision with sprite?
1329     spr_coll |= q[i] | sbit;
1330     } else { // Draw pixel if no collision
1331     p[i] = color;
1332     q[i] = sbit;
1333     }
1334     }
1335    
1336     }
1337     }
1338    
1339     if (ThePrefs.SpriteCollisions) {
1340    
1341     // Check sprite-sprite collisions
1342     if (clx_spr)
1343     clx_spr |= spr_coll;
1344     else {
1345     clx_spr |= spr_coll;
1346     irq_flag |= 0x04;
1347     if (irq_mask & 0x04) {
1348     irq_flag |= 0x80;
1349     the_cpu->TriggerVICIRQ();
1350     }
1351     }
1352    
1353     // Check sprite-background collisions
1354     if (clx_bgr)
1355     clx_bgr |= gfx_coll;
1356     else {
1357     clx_bgr |= gfx_coll;
1358     irq_flag |= 0x02;
1359     if (irq_mask & 0x02) {
1360     irq_flag |= 0x80;
1361     the_cpu->TriggerVICIRQ();
1362     }
1363     }
1364     }
1365     }
1366    
1367    
1368     #ifdef GLOBAL_VARS
1369     static inline int el_update_mc(int raster)
1370     #else
1371     inline int MOS6569::el_update_mc(int raster)
1372     #endif
1373     {
1374     int i, j;
1375     int cycles_used = 0;
1376     uint8 spron = sprite_on;
1377     uint8 spren = me;
1378     uint8 sprye = mye;
1379     uint8 raster8bit = raster;
1380     uint16 *mcp = mc;
1381     uint8 *myp = my;
1382    
1383     // Increment sprite data counters
1384     for (i=0, j=1; i<8; i++, j<<=1, mcp++, myp++) {
1385    
1386     // Sprite enabled?
1387     if (spren & j)
1388    
1389     // Yes, activate if Y position matches raster counter
1390     if (*myp == (raster8bit & 0xff)) {
1391     *mcp = 0;
1392     spron |= j;
1393     } else
1394     goto spr_off;
1395     else
1396     spr_off:
1397     // No, turn sprite off when data counter exceeds 60
1398     // and increment counter
1399     if (*mcp != 63) {
1400     if (sprye & j) { // Y expansion
1401     if (!((*myp ^ raster8bit) & 1)) {
1402     *mcp += 3;
1403     cycles_used += 2;
1404     if (*mcp == 63)
1405     spron &= ~j;
1406     }
1407     } else {
1408     *mcp += 3;
1409     cycles_used += 2;
1410     if (*mcp == 63)
1411     spron &= ~j;
1412     }
1413     }
1414     }
1415    
1416     sprite_on = spron;
1417     return cycles_used;
1418     }
1419    
1420    
1421     #ifdef __POWERPC__
1422     static asm void fastcopy(register uchar *dst, register uchar *src);
1423     static asm void fastcopy(register uchar *dst, register uchar *src)
1424     {
1425     lfd fp0,0(src)
1426     lfd fp1,8(src)
1427     lfd fp2,16(src)
1428     lfd fp3,24(src)
1429     lfd fp4,32(src)
1430     lfd fp5,40(src)
1431     lfd fp6,48(src)
1432     lfd fp7,56(src)
1433     addi src,src,64
1434     stfd fp0,0(dst)
1435     stfd fp1,8(dst)
1436     stfd fp2,16(dst)
1437     stfd fp3,24(dst)
1438     stfd fp4,32(dst)
1439     stfd fp5,40(dst)
1440     stfd fp6,48(dst)
1441     stfd fp7,56(dst)
1442     addi dst,dst,64
1443    
1444     lfd fp0,0(src)
1445     lfd fp1,8(src)
1446     lfd fp2,16(src)
1447     lfd fp3,24(src)
1448     lfd fp4,32(src)
1449     lfd fp5,40(src)
1450     lfd fp6,48(src)
1451     lfd fp7,56(src)
1452     addi src,src,64
1453     stfd fp0,0(dst)
1454     stfd fp1,8(dst)
1455     stfd fp2,16(dst)
1456     stfd fp3,24(dst)
1457     stfd fp4,32(dst)
1458     stfd fp5,40(dst)
1459     stfd fp6,48(dst)
1460     stfd fp7,56(dst)
1461     addi dst,dst,64
1462    
1463     lfd fp0,0(src)
1464     lfd fp1,8(src)
1465     lfd fp2,16(src)
1466     lfd fp3,24(src)
1467     lfd fp4,32(src)
1468     lfd fp5,40(src)
1469     lfd fp6,48(src)
1470     lfd fp7,56(src)
1471     addi src,src,64
1472     stfd fp0,0(dst)
1473     stfd fp1,8(dst)
1474     stfd fp2,16(dst)
1475     stfd fp3,24(dst)
1476     stfd fp4,32(dst)
1477     stfd fp5,40(dst)
1478     stfd fp6,48(dst)
1479     stfd fp7,56(dst)
1480     addi dst,dst,64
1481    
1482     lfd fp0,0(src)
1483     lfd fp1,8(src)
1484     lfd fp2,16(src)
1485     lfd fp3,24(src)
1486     lfd fp4,32(src)
1487     lfd fp5,40(src)
1488     lfd fp6,48(src)
1489     lfd fp7,56(src)
1490     addi src,src,64
1491     stfd fp0,0(dst)
1492     stfd fp1,8(dst)
1493     stfd fp2,16(dst)
1494     stfd fp3,24(dst)
1495     stfd fp4,32(dst)
1496     stfd fp5,40(dst)
1497     stfd fp6,48(dst)
1498     stfd fp7,56(dst)
1499     addi dst,dst,64
1500    
1501     lfd fp0,0(src)
1502     lfd fp1,8(src)
1503     lfd fp2,16(src)
1504     lfd fp3,24(src)
1505     lfd fp4,32(src)
1506     lfd fp5,40(src)
1507     lfd fp6,48(src)
1508     lfd fp7,56(src)
1509     addi src,src,64
1510     stfd fp0,0(dst)
1511     stfd fp1,8(dst)
1512     stfd fp2,16(dst)
1513     stfd fp3,24(dst)
1514     stfd fp4,32(dst)
1515     stfd fp5,40(dst)
1516     stfd fp6,48(dst)
1517     stfd fp7,56(dst)
1518     addi dst,dst,64
1519    
1520     lfd fp0,0(src)
1521     lfd fp1,8(src)
1522     lfd fp2,16(src)
1523     lfd fp3,24(src)
1524     lfd fp4,32(src)
1525     lfd fp5,40(src)
1526     lfd fp6,48(src)
1527     lfd fp7,56(src)
1528     addi src,src,64
1529     stfd fp0,0(dst)
1530     stfd fp1,8(dst)
1531     stfd fp2,16(dst)
1532     stfd fp3,24(dst)
1533     stfd fp4,32(dst)
1534     stfd fp5,40(dst)
1535     stfd fp6,48(dst)
1536     stfd fp7,56(dst)
1537     addi dst,dst,64
1538     blr
1539     }
1540     #endif
1541    
1542    
1543     /*
1544     * Emulate one raster line
1545     */
1546    
1547     int MOS6569::EmulateLine(void)
1548     {
1549     int cycles_left = ThePrefs.NormalCycles; // Cycles left for CPU
1550     bool is_bad_line = false;
1551    
1552     // Get raster counter into local variable for faster access and increment
1553     unsigned int raster = raster_y+1;
1554    
1555     // End of screen reached?
1556     if (raster != TOTAL_RASTERS)
1557     raster_y = raster;
1558     else {
1559     vblank();
1560     raster = 0;
1561     }
1562    
1563     // Trigger raster IRQ if IRQ line reached
1564     if (raster == irq_raster)
1565     raster_irq();
1566    
1567     // In line $30, the DEN bit controls if Bad Lines can occur
1568     if (raster == 0x30)
1569     bad_lines_enabled = ctrl1 & 0x10;
1570    
1571     // Skip frame? Only calculate Bad Lines then
1572     if (frame_skipped) {
1573     if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1574     is_bad_line = true;
1575     cycles_left = ThePrefs.BadLineCycles;
1576     }
1577     goto VIC_nop;
1578     }
1579    
1580     // Within the visible range?
1581     if (raster >= FIRST_DISP_LINE && raster <= LAST_DISP_LINE) {
1582    
1583     // Our output goes here
1584     #ifdef __POWERPC__
1585     uint8 *chunky_ptr = (uint8 *)chunky_tmp;
1586     #else
1587     uint8 *chunky_ptr = chunky_line_start;
1588     #endif
1589    
1590     // Set video counter
1591     vc = vc_base;
1592    
1593     // Bad Line condition?
1594     if (raster >= FIRST_DMA_LINE && raster <= LAST_DMA_LINE && ((raster & 7) == y_scroll) && bad_lines_enabled) {
1595    
1596     // Turn on display
1597     display_state = is_bad_line = true;
1598     cycles_left = ThePrefs.BadLineCycles;
1599     rc = 0;
1600    
1601     // Read and latch 40 bytes from video matrix and color RAM
1602     uint8 *mp = matrix_line - 1;
1603     uint8 *cp = color_line - 1;
1604     int vc1 = vc - 1;
1605     uint8 *mbp = matrix_base + vc1;
1606     uint8 *crp = color_ram + vc1;
1607     for (int i=0; i<40; i++) {
1608     *++mp = *++mbp;
1609     *++cp = *++crp;
1610     }
1611     }
1612    
1613     // Handler upper/lower border
1614     if (raster == dy_stop)
1615     border_on = true;
1616     if (raster == dy_start && (ctrl1 & 0x10)) // Don't turn off border if DEN bit cleared
1617     border_on = false;
1618    
1619     if (!border_on) {
1620    
1621     // Display window contents
1622     uint8 *p = chunky_ptr + COL40_XSTART; // Pointer in chunky display buffer
1623     uint8 *r = fore_mask_buf + COL40_XSTART/8; // Pointer in foreground mask buffer
1624     #ifdef ALIGNMENT_CHECK
1625     uint8 *use_p = ((((int)p) & 3) == 0) ? p : text_chunky_buf;
1626     #endif
1627    
1628     {
1629     p--;
1630     uint8 b0cc = b0c_color;
1631     int limit = x_scroll;
1632     for (int i=0; i<limit; i++) // Background on the left if XScroll>0
1633     *++p = b0cc;
1634     p++;
1635     }
1636    
1637     if (display_state) {
1638     switch (display_idx) {
1639    
1640     case 0: // Standard text
1641     #ifndef CAN_ACCESS_UNALIGNED
1642     #ifdef ALIGNMENT_CHECK
1643     el_std_text(use_p, char_base + rc, r);
1644     if (use_p != p)
1645     memcpy(p, use_p, 8*40);
1646     #else
1647     if (x_scroll) {
1648     el_std_text(text_chunky_buf, char_base + rc, r);
1649     memcpy(p, text_chunky_buf, 8*40);
1650     } else
1651     el_std_text(p, char_base + rc, r);
1652     #endif
1653     #else
1654     el_std_text(p, char_base + rc, r);
1655     #endif
1656     break;
1657    
1658     case 1: // Multicolor text
1659     #ifndef CAN_ACCESS_UNALIGNED
1660     #ifdef ALIGNMENT_CHECK
1661     el_mc_text(use_p, char_base + rc, r);
1662     if (use_p != p)
1663     memcpy(p, use_p, 8*40);
1664     #else
1665     if (x_scroll) {
1666     el_mc_text(text_chunky_buf, char_base + rc, r);
1667     memcpy(p, text_chunky_buf, 8*40);
1668     } else
1669     el_mc_text(p, char_base + rc, r);
1670     #endif
1671     #else
1672     el_mc_text(p, char_base + rc, r);
1673     #endif
1674     break;
1675    
1676     case 2: // Standard bitmap
1677     #ifndef CAN_ACCESS_UNALIGNED
1678     #ifdef ALIGNMENT_CHECK
1679     el_std_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1680     if (use_p != p)
1681     memcpy(p, use_p, 8*40);
1682     #else
1683     if (x_scroll) {
1684     el_std_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1685     memcpy(p, text_chunky_buf, 8*40);
1686     } else
1687     el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1688     #endif
1689     #else
1690     el_std_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1691     #endif
1692     break;
1693    
1694     case 3: // Multicolor bitmap
1695     #ifndef CAN_ACCESS_UNALIGNED
1696     #ifdef ALIGNMENT_CHECK
1697     el_mc_bitmap(use_p, bitmap_base + (vc << 3) + rc, r);
1698     if (use_p != p)
1699     memcpy(p, use_p, 8*40);
1700     #else
1701     if (x_scroll) {
1702     el_mc_bitmap(text_chunky_buf, bitmap_base + (vc << 3) + rc, r);
1703     memcpy(p, text_chunky_buf, 8*40);
1704     } else
1705     el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1706     #endif
1707     #else
1708     el_mc_bitmap(p, bitmap_base + (vc << 3) + rc, r);
1709     #endif
1710     break;
1711    
1712     case 4: // ECM text
1713     #ifndef CAN_ACCESS_UNALIGNED
1714     #ifdef ALIGNMENT_CHECK
1715     el_ecm_text(use_p, char_base + rc, r);
1716     if (use_p != p)
1717     memcpy(p, use_p, 8*40);
1718     #else
1719     if (x_scroll) {
1720     el_ecm_text(text_chunky_buf, char_base + rc, r);
1721     memcpy(p, text_chunky_buf, 8*40);
1722     } else
1723     el_ecm_text(p, char_base + rc, r);
1724     #endif
1725     #else
1726     el_ecm_text(p, char_base + rc, r);
1727     #endif
1728     break;
1729    
1730     default: // Invalid mode (all black)
1731     memset(p, colors[0], 320);
1732     memset(r, 0, 40);
1733     break;
1734     }
1735     vc += 40;
1736    
1737     } else { // Idle state graphics
1738     switch (display_idx) {
1739    
1740     case 0: // Standard text
1741     case 1: // Multicolor text
1742     case 4: // ECM text
1743     #ifndef CAN_ACCESS_UNALIGNED
1744     #ifdef ALIGNMENT_CHECK
1745     el_std_idle(use_p, r);
1746     if (use_p != p) {memcpy(p, use_p, 8*40);}
1747     #else
1748     if (x_scroll) {
1749     el_std_idle(text_chunky_buf, r);
1750     memcpy(p, text_chunky_buf, 8*40);
1751     } else
1752     el_std_idle(p, r);
1753     #endif
1754     #else
1755     el_std_idle(p, r);
1756     #endif
1757     break;
1758    
1759     case 3: // Multicolor bitmap
1760     #ifndef CAN_ACCESS_UNALIGNED
1761     #ifdef ALIGNMENT_CHECK
1762     el_mc_idle(use_p, r);
1763     if (use_p != p) {memcpy(p, use_p, 8*40);}
1764     #else
1765     if (x_scroll) {
1766     el_mc_idle(text_chunky_buf, r);
1767     memcpy(p, text_chunky_buf, 8*40);
1768     } else
1769     el_mc_idle(p, r);
1770     #endif
1771     #else
1772     el_mc_idle(p, r);
1773     #endif
1774     break;
1775    
1776     default: // Invalid mode (all black)
1777     memset(p, colors[0], 320);
1778     memset(r, 0, 40);
1779     break;
1780     }
1781     }
1782    
1783     // Draw sprites
1784     if (sprite_on && ThePrefs.SpritesOn) {
1785    
1786     // Clear sprite collision buffer
1787     uint32 *lp = (uint32 *)spr_coll_buf - 1;
1788     for (int i=0; i<DISPLAY_X/4; i++)
1789     *++lp = 0;
1790    
1791     el_sprites(chunky_ptr);
1792     }
1793    
1794     // Handle left/right border
1795     uint32 *lp = (uint32 *)chunky_ptr - 1;
1796     uint32 c = ec_color_long;
1797     for (int i=0; i<COL40_XSTART/4; i++)
1798     *++lp = c;
1799     lp = (uint32 *)(chunky_ptr + COL40_XSTOP) - 1;
1800     for (int i=0; i<(DISPLAY_X-COL40_XSTOP)/4; i++)
1801     *++lp = c;
1802     if (!border_40_col) {
1803     c = ec_color;
1804     p = chunky_ptr + COL40_XSTART - 1;
1805     for (int i=0; i<COL38_XSTART-COL40_XSTART; i++)
1806     *++p = c;
1807     p = chunky_ptr + COL38_XSTOP - 1;
1808     for (int i=0; i<COL40_XSTOP-COL38_XSTOP; i++)
1809     *++p = c;
1810     }
1811    
1812     #if 0
1813     if (is_bad_line) {
1814     chunky_ptr[DISPLAY_X-2] = colors[7];
1815     chunky_ptr[DISPLAY_X-3] = colors[7];
1816     }
1817     if (rc & 1) {
1818     chunky_ptr[DISPLAY_X-4] = colors[1];
1819     chunky_ptr[DISPLAY_X-5] = colors[1];
1820     }
1821     if (rc & 2) {
1822     chunky_ptr[DISPLAY_X-6] = colors[1];
1823     chunky_ptr[DISPLAY_X-7] = colors[1];
1824     }
1825     if (rc & 4) {
1826     chunky_ptr[DISPLAY_X-8] = colors[1];
1827     chunky_ptr[DISPLAY_X-9] = colors[1];
1828     }
1829     if (ctrl1 & 0x40) {
1830     chunky_ptr[DISPLAY_X-10] = colors[5];
1831     chunky_ptr[DISPLAY_X-11] = colors[5];
1832     }
1833     if (ctrl1 & 0x20) {
1834     chunky_ptr[DISPLAY_X-12] = colors[3];
1835     chunky_ptr[DISPLAY_X-13] = colors[3];
1836     }
1837     if (ctrl2 & 0x10) {
1838     chunky_ptr[DISPLAY_X-14] = colors[2];
1839     chunky_ptr[DISPLAY_X-15] = colors[2];
1840     }
1841     #endif
1842     } else {
1843    
1844     // Display border
1845     uint32 *lp = (uint32 *)chunky_ptr - 1;
1846     uint32 c = ec_color_long;
1847     for (int i=0; i<DISPLAY_X/4; i++)
1848     *++lp = c;
1849     }
1850    
1851     #ifdef __POWERPC__
1852     // Copy temporary buffer to bitmap
1853     fastcopy(chunky_line_start, (uint8 *)chunky_tmp);
1854     #endif
1855    
1856     // Increment pointer in chunky buffer
1857     chunky_line_start += xmod;
1858    
1859     // Increment row counter, go to idle state on overflow
1860     if (rc == 7) {
1861     display_state = false;
1862     vc_base = vc;
1863     } else
1864     rc++;
1865    
1866     if (raster >= FIRST_DMA_LINE-1 && raster <= LAST_DMA_LINE-1 && (((raster+1) & 7) == y_scroll) && bad_lines_enabled)
1867     rc = 0;
1868     }
1869    
1870     VIC_nop:
1871     // Skip this if all sprites are off
1872     if (me | sprite_on)
1873     cycles_left -= el_update_mc(raster);
1874    
1875     return cycles_left;
1876     }