ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/VIC.cpp
Revision: 1.1
Committed: 2003-07-01T17:09:43Z (19 years, 7 months ago) by cebix
Branch: MAIN
Log Message:
imported files

File Contents

# Content
1 /*
2 * VIC.cpp - 6569R5 emulation (line based)
3 *
4 * Frodo (C) 1994-1997,2002 Christian Bauer
5 *
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 }